18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Ricoh RS5C313 RTC device/driver
38c2ecf20Sopenharmony_ci *  Copyright (C) 2007 Nobuhiro Iwamatsu
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  2005-09-19 modifed by kogiidena
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Based on the old drivers/char/rs5c313_rtc.c  by:
88c2ecf20Sopenharmony_ci *  Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
98c2ecf20Sopenharmony_ci *  Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Based on code written by Paul Gortmaker.
128c2ecf20Sopenharmony_ci *  Copyright (C) 1996 Paul Gortmaker
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
158c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
168c2ecf20Sopenharmony_ci * for more details.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Based on other minimal char device drivers, like Alan's
198c2ecf20Sopenharmony_ci * watchdog, Ted's random, etc. etc.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci *	1.07	Paul Gortmaker.
228c2ecf20Sopenharmony_ci *	1.08	Miquel van Smoorenburg: disallow certain things on the
238c2ecf20Sopenharmony_ci *		DEC Alpha as the CMOS clock is also used for other things.
248c2ecf20Sopenharmony_ci *	1.09	Nikita Schmidt: epoch support and some Alpha cleanup.
258c2ecf20Sopenharmony_ci *	1.09a	Pete Zaitcev: Sun SPARC
268c2ecf20Sopenharmony_ci *	1.09b	Jeff Garzik: Modularize, init cleanup
278c2ecf20Sopenharmony_ci *	1.09c	Jeff Garzik: SMP cleanup
288c2ecf20Sopenharmony_ci *	1.10    Paul Barton-Davis: add support for async I/O
298c2ecf20Sopenharmony_ci *	1.10a	Andrea Arcangeli: Alpha updates
308c2ecf20Sopenharmony_ci *	1.10b	Andrew Morton: SMP lock fix
318c2ecf20Sopenharmony_ci *	1.10c	Cesar Barros: SMP locking fixes and cleanup
328c2ecf20Sopenharmony_ci *	1.10d	Paul Gortmaker: delete paranoia check in rtc_exit
338c2ecf20Sopenharmony_ci *	1.10e	Maciej W. Rozycki: Handle DECstation's year weirdness.
348c2ecf20Sopenharmony_ci *      1.11    Takashi Iwai: Kernel access functions
358c2ecf20Sopenharmony_ci *			      rtc_register/rtc_unregister/rtc_control
368c2ecf20Sopenharmony_ci *      1.11a   Daniele Bellucci: Audit create_proc_read_entry in rtc_init
378c2ecf20Sopenharmony_ci *	1.12	Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
388c2ecf20Sopenharmony_ci *		CONFIG_HPET_EMULATE_RTC
398c2ecf20Sopenharmony_ci *	1.13	Nobuhiro Iwamatsu: Updata driver.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#include <linux/module.h>
458c2ecf20Sopenharmony_ci#include <linux/err.h>
468c2ecf20Sopenharmony_ci#include <linux/rtc.h>
478c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
488c2ecf20Sopenharmony_ci#include <linux/bcd.h>
498c2ecf20Sopenharmony_ci#include <linux/delay.h>
508c2ecf20Sopenharmony_ci#include <linux/io.h>
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define DRV_NAME	"rs5c313"
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#ifdef CONFIG_SH_LANDISK
558c2ecf20Sopenharmony_ci/*****************************************************/
568c2ecf20Sopenharmony_ci/* LANDISK dependence part of RS5C313                */
578c2ecf20Sopenharmony_ci/*****************************************************/
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define SCSMR1		0xFFE00000
608c2ecf20Sopenharmony_ci#define SCSCR1		0xFFE00008
618c2ecf20Sopenharmony_ci#define SCSMR1_CA	0x80
628c2ecf20Sopenharmony_ci#define SCSCR1_CKE	0x03
638c2ecf20Sopenharmony_ci#define SCSPTR1		0xFFE0001C
648c2ecf20Sopenharmony_ci#define SCSPTR1_EIO	0x80
658c2ecf20Sopenharmony_ci#define SCSPTR1_SPB1IO	0x08
668c2ecf20Sopenharmony_ci#define SCSPTR1_SPB1DT	0x04
678c2ecf20Sopenharmony_ci#define SCSPTR1_SPB0IO	0x02
688c2ecf20Sopenharmony_ci#define SCSPTR1_SPB0DT	0x01
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define SDA_OEN		SCSPTR1_SPB1IO
718c2ecf20Sopenharmony_ci#define SDA		SCSPTR1_SPB1DT
728c2ecf20Sopenharmony_ci#define SCL_OEN		SCSPTR1_SPB0IO
738c2ecf20Sopenharmony_ci#define SCL		SCSPTR1_SPB0DT
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* RICOH RS5C313 CE port */
768c2ecf20Sopenharmony_ci#define RS5C313_CE	0xB0000003
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* RICOH RS5C313 CE port bit */
798c2ecf20Sopenharmony_ci#define RS5C313_CE_RTCCE	0x02
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* SCSPTR1 data */
828c2ecf20Sopenharmony_ciunsigned char scsptr1_data;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define RS5C313_CEENABLE    __raw_writeb(RS5C313_CE_RTCCE, RS5C313_CE);
858c2ecf20Sopenharmony_ci#define RS5C313_CEDISABLE   __raw_writeb(0x00, RS5C313_CE)
868c2ecf20Sopenharmony_ci#define RS5C313_MISCOP      __raw_writeb(0x02, 0xB0000008)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic void rs5c313_init_port(void)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	/* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */
918c2ecf20Sopenharmony_ci	__raw_writeb(__raw_readb(SCSMR1) & ~SCSMR1_CA, SCSMR1);
928c2ecf20Sopenharmony_ci	__raw_writeb(__raw_readb(SCSCR1) & ~SCSCR1_CKE, SCSCR1);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* And Initialize SCL for RS5C313 clock */
958c2ecf20Sopenharmony_ci	scsptr1_data = __raw_readb(SCSPTR1) | SCL;	/* SCL:H */
968c2ecf20Sopenharmony_ci	__raw_writeb(scsptr1_data, SCSPTR1);
978c2ecf20Sopenharmony_ci	scsptr1_data = __raw_readb(SCSPTR1) | SCL_OEN;	/* SCL output enable */
988c2ecf20Sopenharmony_ci	__raw_writeb(scsptr1_data, SCSPTR1);
998c2ecf20Sopenharmony_ci	RS5C313_CEDISABLE;	/* CE:L */
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void rs5c313_write_data(unsigned char data)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	int i;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
1078c2ecf20Sopenharmony_ci		/* SDA:Write Data */
1088c2ecf20Sopenharmony_ci		scsptr1_data = (scsptr1_data & ~SDA) |
1098c2ecf20Sopenharmony_ci				((((0x80 >> i) & data) >> (7 - i)) << 2);
1108c2ecf20Sopenharmony_ci		__raw_writeb(scsptr1_data, SCSPTR1);
1118c2ecf20Sopenharmony_ci		if (i == 0) {
1128c2ecf20Sopenharmony_ci			scsptr1_data |= SDA_OEN;	/* SDA:output enable */
1138c2ecf20Sopenharmony_ci			__raw_writeb(scsptr1_data, SCSPTR1);
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci		ndelay(700);
1168c2ecf20Sopenharmony_ci		scsptr1_data &= ~SCL;	/* SCL:L */
1178c2ecf20Sopenharmony_ci		__raw_writeb(scsptr1_data, SCSPTR1);
1188c2ecf20Sopenharmony_ci		ndelay(700);
1198c2ecf20Sopenharmony_ci		scsptr1_data |= SCL;	/* SCL:H */
1208c2ecf20Sopenharmony_ci		__raw_writeb(scsptr1_data, SCSPTR1);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	scsptr1_data &= ~SDA_OEN;	/* SDA:output disable */
1248c2ecf20Sopenharmony_ci	__raw_writeb(scsptr1_data, SCSPTR1);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic unsigned char rs5c313_read_data(void)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	int i;
1308c2ecf20Sopenharmony_ci	unsigned char data = 0;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
1338c2ecf20Sopenharmony_ci		ndelay(700);
1348c2ecf20Sopenharmony_ci		/* SDA:Read Data */
1358c2ecf20Sopenharmony_ci		data |= ((__raw_readb(SCSPTR1) & SDA) >> 2) << (7 - i);
1368c2ecf20Sopenharmony_ci		scsptr1_data &= ~SCL;	/* SCL:L */
1378c2ecf20Sopenharmony_ci		__raw_writeb(scsptr1_data, SCSPTR1);
1388c2ecf20Sopenharmony_ci		ndelay(700);
1398c2ecf20Sopenharmony_ci		scsptr1_data |= SCL;	/* SCL:H */
1408c2ecf20Sopenharmony_ci		__raw_writeb(scsptr1_data, SCSPTR1);
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci	return data & 0x0F;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#endif /* CONFIG_SH_LANDISK */
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/*****************************************************/
1488c2ecf20Sopenharmony_ci/* machine independence part of RS5C313              */
1498c2ecf20Sopenharmony_ci/*****************************************************/
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/* RICOH RS5C313 address */
1528c2ecf20Sopenharmony_ci#define RS5C313_ADDR_SEC	0x00
1538c2ecf20Sopenharmony_ci#define RS5C313_ADDR_SEC10	0x01
1548c2ecf20Sopenharmony_ci#define RS5C313_ADDR_MIN	0x02
1558c2ecf20Sopenharmony_ci#define RS5C313_ADDR_MIN10	0x03
1568c2ecf20Sopenharmony_ci#define RS5C313_ADDR_HOUR	0x04
1578c2ecf20Sopenharmony_ci#define RS5C313_ADDR_HOUR10	0x05
1588c2ecf20Sopenharmony_ci#define RS5C313_ADDR_WEEK	0x06
1598c2ecf20Sopenharmony_ci#define RS5C313_ADDR_INTINTVREG	0x07
1608c2ecf20Sopenharmony_ci#define RS5C313_ADDR_DAY	0x08
1618c2ecf20Sopenharmony_ci#define RS5C313_ADDR_DAY10	0x09
1628c2ecf20Sopenharmony_ci#define RS5C313_ADDR_MON	0x0A
1638c2ecf20Sopenharmony_ci#define RS5C313_ADDR_MON10	0x0B
1648c2ecf20Sopenharmony_ci#define RS5C313_ADDR_YEAR	0x0C
1658c2ecf20Sopenharmony_ci#define RS5C313_ADDR_YEAR10	0x0D
1668c2ecf20Sopenharmony_ci#define RS5C313_ADDR_CNTREG	0x0E
1678c2ecf20Sopenharmony_ci#define RS5C313_ADDR_TESTREG	0x0F
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/* RICOH RS5C313 control register */
1708c2ecf20Sopenharmony_ci#define RS5C313_CNTREG_ADJ_BSY	0x01
1718c2ecf20Sopenharmony_ci#define RS5C313_CNTREG_WTEN_XSTP	0x02
1728c2ecf20Sopenharmony_ci#define RS5C313_CNTREG_12_24	0x04
1738c2ecf20Sopenharmony_ci#define RS5C313_CNTREG_CTFG	0x08
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/* RICOH RS5C313 test register */
1768c2ecf20Sopenharmony_ci#define RS5C313_TESTREG_TEST	0x01
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/* RICOH RS5C313 control bit */
1798c2ecf20Sopenharmony_ci#define RS5C313_CNTBIT_READ	0x40
1808c2ecf20Sopenharmony_ci#define RS5C313_CNTBIT_AD	0x20
1818c2ecf20Sopenharmony_ci#define RS5C313_CNTBIT_DT	0x10
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic unsigned char rs5c313_read_reg(unsigned char addr)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	rs5c313_write_data(addr | RS5C313_CNTBIT_READ | RS5C313_CNTBIT_AD);
1878c2ecf20Sopenharmony_ci	return rs5c313_read_data();
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic void rs5c313_write_reg(unsigned char addr, unsigned char data)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	data &= 0x0f;
1938c2ecf20Sopenharmony_ci	rs5c313_write_data(addr | RS5C313_CNTBIT_AD);
1948c2ecf20Sopenharmony_ci	rs5c313_write_data(data | RS5C313_CNTBIT_DT);
1958c2ecf20Sopenharmony_ci	return;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic inline unsigned char rs5c313_read_cntreg(void)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic inline void rs5c313_write_cntreg(unsigned char data)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_CNTREG, data);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic inline void rs5c313_write_intintvreg(unsigned char data)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_INTINTVREG, data);
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int data;
2168c2ecf20Sopenharmony_ci	int cnt;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	cnt = 0;
2198c2ecf20Sopenharmony_ci	while (1) {
2208c2ecf20Sopenharmony_ci		RS5C313_CEENABLE;	/* CE:H */
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		/* Initialize control reg. 24 hour */
2238c2ecf20Sopenharmony_ci		rs5c313_write_cntreg(0x04);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
2268c2ecf20Sopenharmony_ci			break;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		RS5C313_CEDISABLE;
2298c2ecf20Sopenharmony_ci		ndelay(700);	/* CE:L */
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		if (cnt++ > 100) {
2328c2ecf20Sopenharmony_ci			dev_err(dev, "%s: timeout error\n", __func__);
2338c2ecf20Sopenharmony_ci			return -EIO;
2348c2ecf20Sopenharmony_ci		}
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	data = rs5c313_read_reg(RS5C313_ADDR_SEC);
2388c2ecf20Sopenharmony_ci	data |= (rs5c313_read_reg(RS5C313_ADDR_SEC10) << 4);
2398c2ecf20Sopenharmony_ci	tm->tm_sec = bcd2bin(data);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	data = rs5c313_read_reg(RS5C313_ADDR_MIN);
2428c2ecf20Sopenharmony_ci	data |= (rs5c313_read_reg(RS5C313_ADDR_MIN10) << 4);
2438c2ecf20Sopenharmony_ci	tm->tm_min = bcd2bin(data);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	data = rs5c313_read_reg(RS5C313_ADDR_HOUR);
2468c2ecf20Sopenharmony_ci	data |= (rs5c313_read_reg(RS5C313_ADDR_HOUR10) << 4);
2478c2ecf20Sopenharmony_ci	tm->tm_hour = bcd2bin(data);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	data = rs5c313_read_reg(RS5C313_ADDR_DAY);
2508c2ecf20Sopenharmony_ci	data |= (rs5c313_read_reg(RS5C313_ADDR_DAY10) << 4);
2518c2ecf20Sopenharmony_ci	tm->tm_mday = bcd2bin(data);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	data = rs5c313_read_reg(RS5C313_ADDR_MON);
2548c2ecf20Sopenharmony_ci	data |= (rs5c313_read_reg(RS5C313_ADDR_MON10) << 4);
2558c2ecf20Sopenharmony_ci	tm->tm_mon = bcd2bin(data) - 1;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	data = rs5c313_read_reg(RS5C313_ADDR_YEAR);
2588c2ecf20Sopenharmony_ci	data |= (rs5c313_read_reg(RS5C313_ADDR_YEAR10) << 4);
2598c2ecf20Sopenharmony_ci	tm->tm_year = bcd2bin(data);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (tm->tm_year < 70)
2628c2ecf20Sopenharmony_ci		tm->tm_year += 100;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	data = rs5c313_read_reg(RS5C313_ADDR_WEEK);
2658c2ecf20Sopenharmony_ci	tm->tm_wday = bcd2bin(data);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	RS5C313_CEDISABLE;
2688c2ecf20Sopenharmony_ci	ndelay(700);		/* CE:L */
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	int data;
2768c2ecf20Sopenharmony_ci	int cnt;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	cnt = 0;
2798c2ecf20Sopenharmony_ci	/* busy check. */
2808c2ecf20Sopenharmony_ci	while (1) {
2818c2ecf20Sopenharmony_ci		RS5C313_CEENABLE;	/* CE:H */
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		/* Initiatlize control reg. 24 hour */
2848c2ecf20Sopenharmony_ci		rs5c313_write_cntreg(0x04);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
2878c2ecf20Sopenharmony_ci			break;
2888c2ecf20Sopenharmony_ci		RS5C313_MISCOP;
2898c2ecf20Sopenharmony_ci		RS5C313_CEDISABLE;
2908c2ecf20Sopenharmony_ci		ndelay(700);	/* CE:L */
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		if (cnt++ > 100) {
2938c2ecf20Sopenharmony_ci			dev_err(dev, "%s: timeout error\n", __func__);
2948c2ecf20Sopenharmony_ci			return -EIO;
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	data = bin2bcd(tm->tm_sec);
2998c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_SEC, data);
3008c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4));
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	data = bin2bcd(tm->tm_min);
3038c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_MIN, data);
3048c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4));
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	data = bin2bcd(tm->tm_hour);
3078c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_HOUR, data);
3088c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_HOUR10, (data >> 4));
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	data = bin2bcd(tm->tm_mday);
3118c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_DAY, data);
3128c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_DAY10, (data >> 4));
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	data = bin2bcd(tm->tm_mon + 1);
3158c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_MON, data);
3168c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_MON10, (data >> 4));
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	data = bin2bcd(tm->tm_year % 100);
3198c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_YEAR, data);
3208c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_YEAR10, (data >> 4));
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	data = bin2bcd(tm->tm_wday);
3238c2ecf20Sopenharmony_ci	rs5c313_write_reg(RS5C313_ADDR_WEEK, data);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	RS5C313_CEDISABLE;	/* CE:H */
3268c2ecf20Sopenharmony_ci	ndelay(700);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic void rs5c313_check_xstp_bit(void)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct rtc_time tm;
3348c2ecf20Sopenharmony_ci	int cnt;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	RS5C313_CEENABLE;	/* CE:H */
3378c2ecf20Sopenharmony_ci	if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
3388c2ecf20Sopenharmony_ci		/* INT interval reg. OFF */
3398c2ecf20Sopenharmony_ci		rs5c313_write_intintvreg(0x00);
3408c2ecf20Sopenharmony_ci		/* Initialize control reg. 24 hour & adjust */
3418c2ecf20Sopenharmony_ci		rs5c313_write_cntreg(0x07);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		/* busy check. */
3448c2ecf20Sopenharmony_ci		for (cnt = 0; cnt < 100; cnt++) {
3458c2ecf20Sopenharmony_ci			if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
3468c2ecf20Sopenharmony_ci				break;
3478c2ecf20Sopenharmony_ci			RS5C313_MISCOP;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		memset(&tm, 0, sizeof(struct rtc_time));
3518c2ecf20Sopenharmony_ci		tm.tm_mday	= 1;
3528c2ecf20Sopenharmony_ci		tm.tm_mon	= 1 - 1;
3538c2ecf20Sopenharmony_ci		tm.tm_year	= 2000 - 1900;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		rs5c313_rtc_set_time(NULL, &tm);
3568c2ecf20Sopenharmony_ci		pr_err("invalid value, resetting to 1 Jan 2000\n");
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci	RS5C313_CEDISABLE;
3598c2ecf20Sopenharmony_ci	ndelay(700);		/* CE:L */
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic const struct rtc_class_ops rs5c313_rtc_ops = {
3638c2ecf20Sopenharmony_ci	.read_time = rs5c313_rtc_read_time,
3648c2ecf20Sopenharmony_ci	.set_time = rs5c313_rtc_set_time,
3658c2ecf20Sopenharmony_ci};
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic int rs5c313_rtc_probe(struct platform_device *pdev)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct rtc_device *rtc;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	rs5c313_init_port();
3728c2ecf20Sopenharmony_ci	rs5c313_check_xstp_bit();
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	rtc = devm_rtc_device_register(&pdev->dev, "rs5c313", &rs5c313_rtc_ops,
3758c2ecf20Sopenharmony_ci				       THIS_MODULE);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(rtc);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic struct platform_driver rs5c313_rtc_platform_driver = {
3818c2ecf20Sopenharmony_ci	.driver         = {
3828c2ecf20Sopenharmony_ci		.name   = DRV_NAME,
3838c2ecf20Sopenharmony_ci	},
3848c2ecf20Sopenharmony_ci	.probe	= rs5c313_rtc_probe,
3858c2ecf20Sopenharmony_ci};
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cimodule_platform_driver(rs5c313_rtc_platform_driver);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ciMODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
3908c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver");
3918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3928c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME);
393