xref: /linux/drivers/rtc/rtc-m41t94.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28fc2c767SKim B. Heino /*
38fc2c767SKim B. Heino  * Driver for ST M41T94 SPI RTC
48fc2c767SKim B. Heino  *
58fc2c767SKim B. Heino  * Copyright (C) 2008 Kim B. Heino
68fc2c767SKim B. Heino  */
78fc2c767SKim B. Heino 
88fc2c767SKim B. Heino #include <linux/module.h>
98fc2c767SKim B. Heino #include <linux/kernel.h>
108fc2c767SKim B. Heino #include <linux/platform_device.h>
118fc2c767SKim B. Heino #include <linux/rtc.h>
128fc2c767SKim B. Heino #include <linux/spi/spi.h>
138fc2c767SKim B. Heino #include <linux/bcd.h>
148fc2c767SKim B. Heino 
158fc2c767SKim B. Heino #define M41T94_REG_SECONDS	0x01
168fc2c767SKim B. Heino #define M41T94_REG_MINUTES	0x02
178fc2c767SKim B. Heino #define M41T94_REG_HOURS	0x03
188fc2c767SKim B. Heino #define M41T94_REG_WDAY		0x04
198fc2c767SKim B. Heino #define M41T94_REG_DAY		0x05
208fc2c767SKim B. Heino #define M41T94_REG_MONTH	0x06
218fc2c767SKim B. Heino #define M41T94_REG_YEAR		0x07
228fc2c767SKim B. Heino #define M41T94_REG_HT		0x0c
238fc2c767SKim B. Heino 
248fc2c767SKim B. Heino #define M41T94_BIT_HALT		0x40
258fc2c767SKim B. Heino #define M41T94_BIT_STOP		0x80
268fc2c767SKim B. Heino #define M41T94_BIT_CB		0x40
278fc2c767SKim B. Heino #define M41T94_BIT_CEB		0x80
288fc2c767SKim B. Heino 
m41t94_set_time(struct device * dev,struct rtc_time * tm)298fc2c767SKim B. Heino static int m41t94_set_time(struct device *dev, struct rtc_time *tm)
308fc2c767SKim B. Heino {
318fc2c767SKim B. Heino 	struct spi_device *spi = to_spi_device(dev);
328fc2c767SKim B. Heino 	u8 buf[8]; /* write cmd + 7 registers */
338fc2c767SKim B. Heino 
348fc2c767SKim B. Heino 	dev_dbg(dev, "%s secs=%d, mins=%d, "
358fc2c767SKim B. Heino 		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
368fc2c767SKim B. Heino 		"write", tm->tm_sec, tm->tm_min,
378fc2c767SKim B. Heino 		tm->tm_hour, tm->tm_mday,
388fc2c767SKim B. Heino 		tm->tm_mon, tm->tm_year, tm->tm_wday);
398fc2c767SKim B. Heino 
408fc2c767SKim B. Heino 	buf[0] = 0x80 | M41T94_REG_SECONDS; /* write time + date */
41fe20ba70SAdrian Bunk 	buf[M41T94_REG_SECONDS] = bin2bcd(tm->tm_sec);
42fe20ba70SAdrian Bunk 	buf[M41T94_REG_MINUTES] = bin2bcd(tm->tm_min);
43fe20ba70SAdrian Bunk 	buf[M41T94_REG_HOURS]   = bin2bcd(tm->tm_hour);
44fe20ba70SAdrian Bunk 	buf[M41T94_REG_WDAY]    = bin2bcd(tm->tm_wday + 1);
45fe20ba70SAdrian Bunk 	buf[M41T94_REG_DAY]     = bin2bcd(tm->tm_mday);
46fe20ba70SAdrian Bunk 	buf[M41T94_REG_MONTH]   = bin2bcd(tm->tm_mon + 1);
478fc2c767SKim B. Heino 
488fc2c767SKim B. Heino 	buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB;
498fc2c767SKim B. Heino 	if (tm->tm_year >= 100)
508fc2c767SKim B. Heino 		buf[M41T94_REG_HOURS] |= M41T94_BIT_CB;
51fe20ba70SAdrian Bunk 	buf[M41T94_REG_YEAR] = bin2bcd(tm->tm_year % 100);
528fc2c767SKim B. Heino 
538fc2c767SKim B. Heino 	return spi_write(spi, buf, 8);
548fc2c767SKim B. Heino }
558fc2c767SKim B. Heino 
m41t94_read_time(struct device * dev,struct rtc_time * tm)568fc2c767SKim B. Heino static int m41t94_read_time(struct device *dev, struct rtc_time *tm)
578fc2c767SKim B. Heino {
588fc2c767SKim B. Heino 	struct spi_device *spi = to_spi_device(dev);
598fc2c767SKim B. Heino 	u8 buf[2];
608fc2c767SKim B. Heino 	int ret, hour;
618fc2c767SKim B. Heino 
628fc2c767SKim B. Heino 	/* clear halt update bit */
638fc2c767SKim B. Heino 	ret = spi_w8r8(spi, M41T94_REG_HT);
648fc2c767SKim B. Heino 	if (ret < 0)
658fc2c767SKim B. Heino 		return ret;
668fc2c767SKim B. Heino 	if (ret & M41T94_BIT_HALT) {
678fc2c767SKim B. Heino 		buf[0] = 0x80 | M41T94_REG_HT;
688fc2c767SKim B. Heino 		buf[1] = ret & ~M41T94_BIT_HALT;
698fc2c767SKim B. Heino 		spi_write(spi, buf, 2);
708fc2c767SKim B. Heino 	}
718fc2c767SKim B. Heino 
728fc2c767SKim B. Heino 	/* clear stop bit */
738fc2c767SKim B. Heino 	ret = spi_w8r8(spi, M41T94_REG_SECONDS);
748fc2c767SKim B. Heino 	if (ret < 0)
758fc2c767SKim B. Heino 		return ret;
768fc2c767SKim B. Heino 	if (ret & M41T94_BIT_STOP) {
778fc2c767SKim B. Heino 		buf[0] = 0x80 | M41T94_REG_SECONDS;
788fc2c767SKim B. Heino 		buf[1] = ret & ~M41T94_BIT_STOP;
798fc2c767SKim B. Heino 		spi_write(spi, buf, 2);
808fc2c767SKim B. Heino 	}
818fc2c767SKim B. Heino 
82fe20ba70SAdrian Bunk 	tm->tm_sec  = bcd2bin(spi_w8r8(spi, M41T94_REG_SECONDS));
83fe20ba70SAdrian Bunk 	tm->tm_min  = bcd2bin(spi_w8r8(spi, M41T94_REG_MINUTES));
848fc2c767SKim B. Heino 	hour = spi_w8r8(spi, M41T94_REG_HOURS);
85fe20ba70SAdrian Bunk 	tm->tm_hour = bcd2bin(hour & 0x3f);
86fe20ba70SAdrian Bunk 	tm->tm_wday = bcd2bin(spi_w8r8(spi, M41T94_REG_WDAY)) - 1;
87fe20ba70SAdrian Bunk 	tm->tm_mday = bcd2bin(spi_w8r8(spi, M41T94_REG_DAY));
88fe20ba70SAdrian Bunk 	tm->tm_mon  = bcd2bin(spi_w8r8(spi, M41T94_REG_MONTH)) - 1;
89fe20ba70SAdrian Bunk 	tm->tm_year = bcd2bin(spi_w8r8(spi, M41T94_REG_YEAR));
908fc2c767SKim B. Heino 	if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB))
918fc2c767SKim B. Heino 		tm->tm_year += 100;
928fc2c767SKim B. Heino 
938fc2c767SKim B. Heino 	dev_dbg(dev, "%s secs=%d, mins=%d, "
948fc2c767SKim B. Heino 		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
958fc2c767SKim B. Heino 		"read", tm->tm_sec, tm->tm_min,
968fc2c767SKim B. Heino 		tm->tm_hour, tm->tm_mday,
978fc2c767SKim B. Heino 		tm->tm_mon, tm->tm_year, tm->tm_wday);
988fc2c767SKim B. Heino 
9922652ba7SAlexandre Belloni 	return 0;
1008fc2c767SKim B. Heino }
1018fc2c767SKim B. Heino 
1028fc2c767SKim B. Heino static const struct rtc_class_ops m41t94_rtc_ops = {
1038fc2c767SKim B. Heino 	.read_time	= m41t94_read_time,
1048fc2c767SKim B. Heino 	.set_time	= m41t94_set_time,
1058fc2c767SKim B. Heino };
1068fc2c767SKim B. Heino 
1078fc2c767SKim B. Heino static struct spi_driver m41t94_driver;
1088fc2c767SKim B. Heino 
m41t94_probe(struct spi_device * spi)1095a167f45SGreg Kroah-Hartman static int m41t94_probe(struct spi_device *spi)
1108fc2c767SKim B. Heino {
1118fc2c767SKim B. Heino 	struct rtc_device *rtc;
1128fc2c767SKim B. Heino 	int res;
1138fc2c767SKim B. Heino 
1148fc2c767SKim B. Heino 	spi->bits_per_word = 8;
1158fc2c767SKim B. Heino 	spi_setup(spi);
1168fc2c767SKim B. Heino 
1178fc2c767SKim B. Heino 	res = spi_w8r8(spi, M41T94_REG_SECONDS);
1188fc2c767SKim B. Heino 	if (res < 0) {
1198fc2c767SKim B. Heino 		dev_err(&spi->dev, "not found.\n");
1208fc2c767SKim B. Heino 		return res;
1218fc2c767SKim B. Heino 	}
1228fc2c767SKim B. Heino 
123fb320d0aSJingoo Han 	rtc = devm_rtc_device_register(&spi->dev, m41t94_driver.driver.name,
124fb320d0aSJingoo Han 					&m41t94_rtc_ops, THIS_MODULE);
1258fc2c767SKim B. Heino 	if (IS_ERR(rtc))
1268fc2c767SKim B. Heino 		return PTR_ERR(rtc);
1278fc2c767SKim B. Heino 
128ee62474dSJingoo Han 	spi_set_drvdata(spi, rtc);
1298fc2c767SKim B. Heino 
1308fc2c767SKim B. Heino 	return 0;
1318fc2c767SKim B. Heino }
1328fc2c767SKim B. Heino 
1338fc2c767SKim B. Heino static struct spi_driver m41t94_driver = {
1348fc2c767SKim B. Heino 	.driver = {
1358fc2c767SKim B. Heino 		.name	= "rtc-m41t94",
1368fc2c767SKim B. Heino 	},
1378fc2c767SKim B. Heino 	.probe	= m41t94_probe,
1388fc2c767SKim B. Heino };
1398fc2c767SKim B. Heino 
140109e9418SAxel Lin module_spi_driver(m41t94_driver);
1418fc2c767SKim B. Heino 
1428fc2c767SKim B. Heino MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>");
1438fc2c767SKim B. Heino MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC");
1448fc2c767SKim B. Heino MODULE_LICENSE("GPL");
145e0626e38SAnton Vorontsov MODULE_ALIAS("spi:rtc-m41t94");
146