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