xref: /OK3568_Linux_fs/kernel/drivers/rtc/rtc-m41t93.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Driver for ST M41T93 SPI RTC
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/bcd.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/platform_device.h>
13*4882a593Smuzhiyun #include <linux/rtc.h>
14*4882a593Smuzhiyun #include <linux/spi/spi.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define M41T93_REG_SSEC			0
17*4882a593Smuzhiyun #define M41T93_REG_ST_SEC		1
18*4882a593Smuzhiyun #define M41T93_REG_MIN			2
19*4882a593Smuzhiyun #define M41T93_REG_CENT_HOUR		3
20*4882a593Smuzhiyun #define M41T93_REG_WDAY			4
21*4882a593Smuzhiyun #define M41T93_REG_DAY			5
22*4882a593Smuzhiyun #define M41T93_REG_MON			6
23*4882a593Smuzhiyun #define M41T93_REG_YEAR			7
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define M41T93_REG_ALM_HOUR_HT		0xc
27*4882a593Smuzhiyun #define M41T93_REG_FLAGS		0xf
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define M41T93_FLAG_ST			(1 << 7)
30*4882a593Smuzhiyun #define M41T93_FLAG_OF			(1 << 2)
31*4882a593Smuzhiyun #define M41T93_FLAG_BL			(1 << 4)
32*4882a593Smuzhiyun #define M41T93_FLAG_HT			(1 << 6)
33*4882a593Smuzhiyun 
m41t93_set_reg(struct spi_device * spi,u8 addr,u8 data)34*4882a593Smuzhiyun static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	u8 buf[2];
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	/* MSB must be '1' to write */
39*4882a593Smuzhiyun 	buf[0] = addr | 0x80;
40*4882a593Smuzhiyun 	buf[1] = data;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	return spi_write(spi, buf, sizeof(buf));
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
m41t93_set_time(struct device * dev,struct rtc_time * tm)45*4882a593Smuzhiyun static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	struct spi_device *spi = to_spi_device(dev);
48*4882a593Smuzhiyun 	int tmp;
49*4882a593Smuzhiyun 	u8 buf[9] = {0x80};        /* write cmd + 8 data bytes */
50*4882a593Smuzhiyun 	u8 * const data = &buf[1]; /* ptr to first data byte */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	dev_dbg(dev, "%s secs=%d, mins=%d, "
53*4882a593Smuzhiyun 		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
54*4882a593Smuzhiyun 		"write", tm->tm_sec, tm->tm_min,
55*4882a593Smuzhiyun 		tm->tm_hour, tm->tm_mday,
56*4882a593Smuzhiyun 		tm->tm_mon, tm->tm_year, tm->tm_wday);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	if (tm->tm_year < 100) {
59*4882a593Smuzhiyun 		dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n");
60*4882a593Smuzhiyun 		return -EINVAL;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
64*4882a593Smuzhiyun 	if (tmp < 0)
65*4882a593Smuzhiyun 		return tmp;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if (tmp & M41T93_FLAG_OF) {
68*4882a593Smuzhiyun 		dev_warn(&spi->dev, "OF bit is set, resetting.\n");
69*4882a593Smuzhiyun 		m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 		tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
72*4882a593Smuzhiyun 		if (tmp < 0) {
73*4882a593Smuzhiyun 			return tmp;
74*4882a593Smuzhiyun 		} else if (tmp & M41T93_FLAG_OF) {
75*4882a593Smuzhiyun 			/* OF cannot be immediately reset: oscillator has to be
76*4882a593Smuzhiyun 			 * restarted. */
77*4882a593Smuzhiyun 			u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 			dev_warn(&spi->dev,
80*4882a593Smuzhiyun 				 "OF bit is still set, kickstarting clock.\n");
81*4882a593Smuzhiyun 			m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
82*4882a593Smuzhiyun 			reset_osc &= ~M41T93_FLAG_ST;
83*4882a593Smuzhiyun 			m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
84*4882a593Smuzhiyun 		}
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	data[M41T93_REG_SSEC]		= 0;
88*4882a593Smuzhiyun 	data[M41T93_REG_ST_SEC]		= bin2bcd(tm->tm_sec);
89*4882a593Smuzhiyun 	data[M41T93_REG_MIN]		= bin2bcd(tm->tm_min);
90*4882a593Smuzhiyun 	data[M41T93_REG_CENT_HOUR]	= bin2bcd(tm->tm_hour) |
91*4882a593Smuzhiyun 						((tm->tm_year/100-1) << 6);
92*4882a593Smuzhiyun 	data[M41T93_REG_DAY]		= bin2bcd(tm->tm_mday);
93*4882a593Smuzhiyun 	data[M41T93_REG_WDAY]		= bin2bcd(tm->tm_wday + 1);
94*4882a593Smuzhiyun 	data[M41T93_REG_MON]		= bin2bcd(tm->tm_mon + 1);
95*4882a593Smuzhiyun 	data[M41T93_REG_YEAR]		= bin2bcd(tm->tm_year % 100);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return spi_write(spi, buf, sizeof(buf));
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 
m41t93_get_time(struct device * dev,struct rtc_time * tm)101*4882a593Smuzhiyun static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	struct spi_device *spi = to_spi_device(dev);
104*4882a593Smuzhiyun 	const u8 start_addr = 0;
105*4882a593Smuzhiyun 	u8 buf[8];
106*4882a593Smuzhiyun 	int century_after_1900;
107*4882a593Smuzhiyun 	int tmp;
108*4882a593Smuzhiyun 	int ret = 0;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	/* Check status of clock. Two states must be considered:
111*4882a593Smuzhiyun 	   1. halt bit (HT) is set: the clock is running but update of readout
112*4882a593Smuzhiyun 	      registers has been disabled due to power failure. This is normal
113*4882a593Smuzhiyun 	      case after poweron. Time is valid after resetting HT bit.
114*4882a593Smuzhiyun 	   2. oscillator fail bit (OF) is set: time is invalid.
115*4882a593Smuzhiyun 	*/
116*4882a593Smuzhiyun 	tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
117*4882a593Smuzhiyun 	if (tmp < 0)
118*4882a593Smuzhiyun 		return tmp;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (tmp & M41T93_FLAG_HT) {
121*4882a593Smuzhiyun 		dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n");
122*4882a593Smuzhiyun 		m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT,
123*4882a593Smuzhiyun 			       tmp & ~M41T93_FLAG_HT);
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
127*4882a593Smuzhiyun 	if (tmp < 0)
128*4882a593Smuzhiyun 		return tmp;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (tmp & M41T93_FLAG_OF) {
131*4882a593Smuzhiyun 		ret = -EINVAL;
132*4882a593Smuzhiyun 		dev_warn(&spi->dev, "OF bit is set, write time to restart.\n");
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (tmp & M41T93_FLAG_BL)
136*4882a593Smuzhiyun 		dev_warn(&spi->dev, "BL bit is set, replace battery.\n");
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	/* read actual time/date */
139*4882a593Smuzhiyun 	tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf));
140*4882a593Smuzhiyun 	if (tmp < 0)
141*4882a593Smuzhiyun 		return tmp;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	tm->tm_sec	= bcd2bin(buf[M41T93_REG_ST_SEC]);
144*4882a593Smuzhiyun 	tm->tm_min	= bcd2bin(buf[M41T93_REG_MIN]);
145*4882a593Smuzhiyun 	tm->tm_hour	= bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f);
146*4882a593Smuzhiyun 	tm->tm_mday	= bcd2bin(buf[M41T93_REG_DAY]);
147*4882a593Smuzhiyun 	tm->tm_mon	= bcd2bin(buf[M41T93_REG_MON]) - 1;
148*4882a593Smuzhiyun 	tm->tm_wday	= bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1;
151*4882a593Smuzhiyun 	tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	dev_dbg(dev, "%s secs=%d, mins=%d, "
154*4882a593Smuzhiyun 		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
155*4882a593Smuzhiyun 		"read", tm->tm_sec, tm->tm_min,
156*4882a593Smuzhiyun 		tm->tm_hour, tm->tm_mday,
157*4882a593Smuzhiyun 		tm->tm_mon, tm->tm_year, tm->tm_wday);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	return ret;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static const struct rtc_class_ops m41t93_rtc_ops = {
164*4882a593Smuzhiyun 	.read_time	= m41t93_get_time,
165*4882a593Smuzhiyun 	.set_time	= m41t93_set_time,
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun static struct spi_driver m41t93_driver;
169*4882a593Smuzhiyun 
m41t93_probe(struct spi_device * spi)170*4882a593Smuzhiyun static int m41t93_probe(struct spi_device *spi)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct rtc_device *rtc;
173*4882a593Smuzhiyun 	int res;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	spi->bits_per_word = 8;
176*4882a593Smuzhiyun 	spi_setup(spi);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	res = spi_w8r8(spi, M41T93_REG_WDAY);
179*4882a593Smuzhiyun 	if (res < 0 || (res & 0xf8) != 0) {
180*4882a593Smuzhiyun 		dev_err(&spi->dev, "not found 0x%x.\n", res);
181*4882a593Smuzhiyun 		return -ENODEV;
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
185*4882a593Smuzhiyun 					&m41t93_rtc_ops, THIS_MODULE);
186*4882a593Smuzhiyun 	if (IS_ERR(rtc))
187*4882a593Smuzhiyun 		return PTR_ERR(rtc);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	spi_set_drvdata(spi, rtc);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun static struct spi_driver m41t93_driver = {
195*4882a593Smuzhiyun 	.driver = {
196*4882a593Smuzhiyun 		.name	= "rtc-m41t93",
197*4882a593Smuzhiyun 	},
198*4882a593Smuzhiyun 	.probe	= m41t93_probe,
199*4882a593Smuzhiyun };
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun module_spi_driver(m41t93_driver);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
204*4882a593Smuzhiyun MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
205*4882a593Smuzhiyun MODULE_LICENSE("GPL");
206*4882a593Smuzhiyun MODULE_ALIAS("spi:rtc-m41t93");
207