2008-11-13 00:27:06 +03:00
/*
* An I2C driver for the Epson RX8581 RTC
*
2010-04-14 12:24:16 +04:00
* Author : Martyn Welch < martyn . welch @ ge . com >
* Copyright 2008 GE Intelligent Platforms Embedded Systems , Inc .
2008-11-13 00:27:06 +03:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* Based on : rtc - pcf8563 . c ( An I2C driver for the Philips PCF8563 RTC )
* Copyright 2005 - 06 Tower Technologies
*/
# include <linux/module.h>
# include <linux/i2c.h>
# include <linux/bcd.h>
2018-05-17 23:33:31 +03:00
# include <linux/regmap.h>
2008-11-13 00:27:06 +03:00
# include <linux/rtc.h>
# include <linux/log2.h>
# define RX8581_REG_SC 0x00 /* Second in BCD */
# define RX8581_REG_MN 0x01 /* Minute in BCD */
# define RX8581_REG_HR 0x02 /* Hour in BCD */
# define RX8581_REG_DW 0x03 /* Day of Week */
# define RX8581_REG_DM 0x04 /* Day of Month in BCD */
# define RX8581_REG_MO 0x05 /* Month in BCD */
# define RX8581_REG_YR 0x06 /* Year in BCD */
# define RX8581_REG_RAM 0x07 /* RAM */
# define RX8581_REG_AMN 0x08 /* Alarm Min in BCD*/
# define RX8581_REG_AHR 0x09 /* Alarm Hour in BCD */
# define RX8581_REG_ADM 0x0A
# define RX8581_REG_ADW 0x0A
# define RX8581_REG_TMR0 0x0B
# define RX8581_REG_TMR1 0x0C
# define RX8581_REG_EXT 0x0D /* Extension Register */
# define RX8581_REG_FLAG 0x0E /* Flag Register */
# define RX8581_REG_CTRL 0x0F /* Control Register */
/* Flag Register bit definitions */
# define RX8581_FLAG_UF 0x20 /* Update */
# define RX8581_FLAG_TF 0x10 /* Timer */
# define RX8581_FLAG_AF 0x08 /* Alarm */
# define RX8581_FLAG_VLF 0x02 /* Voltage Low */
/* Control Register bit definitions */
# define RX8581_CTRL_UIE 0x20 /* Update Interrupt Enable */
# define RX8581_CTRL_TIE 0x10 /* Timer Interrupt Enable */
# define RX8581_CTRL_AIE 0x08 /* Alarm Interrupt Enable */
# define RX8581_CTRL_STOP 0x02 /* STOP bit */
# define RX8581_CTRL_RESET 0x01 /* RESET bit */
2014-01-24 03:55:20 +04:00
struct rx8581 {
2018-05-17 23:33:31 +03:00
struct regmap * regmap ;
2014-01-24 03:55:20 +04:00
struct rtc_device * rtc ;
} ;
2008-11-13 00:27:06 +03:00
/*
* In the routines that deal directly with the rx8581 hardware , we use
* rtc_time - - month 0 - 11 , hour 0 - 23 , yr = calendar year - epoch .
*/
2018-05-17 23:33:28 +03:00
static int rx8581_rtc_read_time ( struct device * dev , struct rtc_time * tm )
2008-11-13 00:27:06 +03:00
{
2018-05-17 23:33:28 +03:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2008-11-13 00:27:06 +03:00
unsigned char date [ 7 ] ;
2018-05-17 23:33:31 +03:00
unsigned int data ;
int err ;
2014-01-24 03:55:20 +04:00
struct rx8581 * rx8581 = i2c_get_clientdata ( client ) ;
2008-11-13 00:27:06 +03:00
/* First we ensure that the "update flag" is not set, we read the
* time and date then re - read the " update flag " . If the update flag
* has been set , we know that the time has changed during the read so
* we repeat the whole process again .
*/
2018-05-17 23:33:31 +03:00
err = regmap_read ( rx8581 - > regmap , RX8581_REG_FLAG , & data ) ;
if ( err < 0 )
return err ;
2008-11-13 00:27:06 +03:00
2018-05-17 23:33:30 +03:00
if ( data & RX8581_FLAG_VLF ) {
dev_warn ( dev ,
" low voltage detected, date/time is not reliable. \n " ) ;
return - EINVAL ;
}
2008-11-13 00:27:06 +03:00
do {
/* If update flag set, clear it */
if ( data & RX8581_FLAG_UF ) {
2018-05-17 23:33:31 +03:00
err = regmap_write ( rx8581 - > regmap , RX8581_REG_FLAG ,
data & ~ RX8581_FLAG_UF ) ;
if ( err < 0 )
return err ;
2008-11-13 00:27:06 +03:00
}
/* Now read time and date */
2018-05-17 23:33:31 +03:00
err = regmap_bulk_read ( rx8581 - > regmap , RX8581_REG_SC , date ,
sizeof ( date ) ) ;
if ( err < 0 )
return err ;
2008-11-13 00:27:06 +03:00
/* Check flag register */
2018-05-17 23:33:31 +03:00
err = regmap_read ( rx8581 - > regmap , RX8581_REG_FLAG , & data ) ;
if ( err < 0 )
return err ;
2008-11-13 00:27:06 +03:00
} while ( data & RX8581_FLAG_UF ) ;
2018-05-17 23:33:29 +03:00
dev_dbg ( dev , " %s: raw data is sec=%02x, min=%02x, hr=%02x, "
2008-11-13 00:27:06 +03:00
" wday=%02x, mday=%02x, mon=%02x, year=%02x \n " ,
__func__ ,
date [ 0 ] , date [ 1 ] , date [ 2 ] , date [ 3 ] , date [ 4 ] , date [ 5 ] , date [ 6 ] ) ;
tm - > tm_sec = bcd2bin ( date [ RX8581_REG_SC ] & 0x7F ) ;
tm - > tm_min = bcd2bin ( date [ RX8581_REG_MN ] & 0x7F ) ;
tm - > tm_hour = bcd2bin ( date [ RX8581_REG_HR ] & 0x3F ) ; /* rtc hr 0-23 */
tm - > tm_wday = ilog2 ( date [ RX8581_REG_DW ] & 0x7F ) ;
tm - > tm_mday = bcd2bin ( date [ RX8581_REG_DM ] & 0x3F ) ;
tm - > tm_mon = bcd2bin ( date [ RX8581_REG_MO ] & 0x1F ) - 1 ; /* rtc mn 1-12 */
2018-05-17 23:33:27 +03:00
tm - > tm_year = bcd2bin ( date [ RX8581_REG_YR ] ) + 100 ;
2008-11-13 00:27:06 +03:00
2018-05-17 23:33:29 +03:00
dev_dbg ( dev , " %s: tm is secs=%d, mins=%d, hours=%d, "
2008-11-13 00:27:06 +03:00
" mday=%d, mon=%d, year=%d, wday=%d \n " ,
__func__ ,
tm - > tm_sec , tm - > tm_min , tm - > tm_hour ,
tm - > tm_mday , tm - > tm_mon , tm - > tm_year , tm - > tm_wday ) ;
2018-02-21 02:25:18 +03:00
return 0 ;
2008-11-13 00:27:06 +03:00
}
2018-05-17 23:33:28 +03:00
static int rx8581_rtc_set_time ( struct device * dev , struct rtc_time * tm )
2008-11-13 00:27:06 +03:00
{
2018-05-17 23:33:28 +03:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2018-05-17 23:33:31 +03:00
int err ;
2008-11-13 00:27:06 +03:00
unsigned char buf [ 7 ] ;
2014-01-24 03:55:20 +04:00
struct rx8581 * rx8581 = i2c_get_clientdata ( client ) ;
2008-11-13 00:27:06 +03:00
2018-05-17 23:33:29 +03:00
dev_dbg ( dev , " %s: secs=%d, mins=%d, hours=%d, "
2008-11-13 00:27:06 +03:00
" mday=%d, mon=%d, year=%d, wday=%d \n " ,
__func__ ,
tm - > tm_sec , tm - > tm_min , tm - > tm_hour ,
tm - > tm_mday , tm - > tm_mon , tm - > tm_year , tm - > tm_wday ) ;
/* hours, minutes and seconds */
buf [ RX8581_REG_SC ] = bin2bcd ( tm - > tm_sec ) ;
buf [ RX8581_REG_MN ] = bin2bcd ( tm - > tm_min ) ;
buf [ RX8581_REG_HR ] = bin2bcd ( tm - > tm_hour ) ;
buf [ RX8581_REG_DM ] = bin2bcd ( tm - > tm_mday ) ;
/* month, 1 - 12 */
buf [ RX8581_REG_MO ] = bin2bcd ( tm - > tm_mon + 1 ) ;
/* year and century */
2018-05-17 23:33:27 +03:00
buf [ RX8581_REG_YR ] = bin2bcd ( tm - > tm_year - 100 ) ;
2008-11-13 00:27:06 +03:00
buf [ RX8581_REG_DW ] = ( 0x1 < < tm - > tm_wday ) ;
/* Stop the clock */
2018-05-17 23:33:31 +03:00
err = regmap_update_bits ( rx8581 - > regmap , RX8581_REG_CTRL ,
RX8581_CTRL_STOP , RX8581_CTRL_STOP ) ;
if ( err < 0 )
return err ;
2008-11-13 00:27:06 +03:00
/* write register's data */
2018-05-17 23:33:31 +03:00
err = regmap_bulk_write ( rx8581 - > regmap , RX8581_REG_SC ,
buf , sizeof ( buf ) ) ;
if ( err < 0 )
return err ;
2008-11-13 00:27:06 +03:00
2010-07-28 00:18:02 +04:00
/* get VLF and clear it */
2018-05-17 23:33:31 +03:00
err = regmap_update_bits ( rx8581 - > regmap , RX8581_REG_FLAG ,
RX8581_FLAG_VLF , 0 ) ;
if ( err < 0 )
return err ;
2010-07-28 00:18:02 +04:00
2008-11-13 00:27:06 +03:00
/* Restart the clock */
2018-05-17 23:33:31 +03:00
return regmap_update_bits ( rx8581 - > regmap , RX8581_REG_CTRL ,
RX8581_CTRL_STOP , 0 ) ;
2008-11-13 00:27:06 +03:00
}
static const struct rtc_class_ops rx8581_rtc_ops = {
. read_time = rx8581_rtc_read_time ,
. set_time = rx8581_rtc_set_time ,
} ;
2012-12-22 01:09:38 +04:00
static int rx8581_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2008-11-13 00:27:06 +03:00
{
2014-01-24 03:55:20 +04:00
struct rx8581 * rx8581 ;
2018-05-17 23:33:31 +03:00
static const struct regmap_config config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = 0xf ,
} ;
2008-11-13 00:27:06 +03:00
dev_dbg ( & client - > dev , " %s \n " , __func__ ) ;
2014-01-24 03:55:20 +04:00
rx8581 = devm_kzalloc ( & client - > dev , sizeof ( struct rx8581 ) , GFP_KERNEL ) ;
if ( ! rx8581 )
return - ENOMEM ;
2008-11-13 00:27:06 +03:00
2014-01-24 03:55:20 +04:00
i2c_set_clientdata ( client , rx8581 ) ;
2018-05-17 23:33:31 +03:00
rx8581 - > regmap = devm_regmap_init_i2c ( client , & config ) ;
if ( IS_ERR ( rx8581 - > regmap ) )
return PTR_ERR ( rx8581 - > regmap ) ;
2008-11-13 00:27:06 +03:00
2018-05-17 23:33:25 +03:00
rx8581 - > rtc = devm_rtc_allocate_device ( & client - > dev ) ;
if ( IS_ERR ( rx8581 - > rtc ) )
2014-01-24 03:55:20 +04:00
return PTR_ERR ( rx8581 - > rtc ) ;
2008-11-13 00:27:06 +03:00
2018-05-17 23:33:25 +03:00
rx8581 - > rtc - > ops = & rx8581_rtc_ops ;
2018-05-17 23:33:26 +03:00
rx8581 - > rtc - > range_min = RTC_TIMESTAMP_BEGIN_2000 ;
rx8581 - > rtc - > range_max = RTC_TIMESTAMP_END_2099 ;
2018-05-17 23:33:27 +03:00
rx8581 - > rtc - > start_secs = 0 ;
rx8581 - > rtc - > set_start_time = true ;
2018-05-17 23:33:25 +03:00
return rtc_register_device ( rx8581 - > rtc ) ;
2008-11-13 00:27:06 +03:00
}
static const struct i2c_device_id rx8581_id [ ] = {
{ " rx8581 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , rx8581_id ) ;
2017-03-03 17:29:22 +03:00
static const struct of_device_id rx8581_of_match [ ] = {
{ . compatible = " epson,rx8581 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , rx8581_of_match ) ;
2008-11-13 00:27:06 +03:00
static struct i2c_driver rx8581_driver = {
. driver = {
. name = " rtc-rx8581 " ,
2017-03-03 17:29:22 +03:00
. of_match_table = of_match_ptr ( rx8581_of_match ) ,
2008-11-13 00:27:06 +03:00
} ,
. probe = rx8581_probe ,
. id_table = rx8581_id ,
} ;
2012-03-24 02:02:31 +04:00
module_i2c_driver ( rx8581_driver ) ;
2008-11-13 00:27:06 +03:00
2010-04-14 12:24:16 +04:00
MODULE_AUTHOR ( " Martyn Welch <martyn.welch@ge.com> " ) ;
2008-11-13 00:27:06 +03:00
MODULE_DESCRIPTION ( " Epson RX-8581 RTC driver " ) ;
MODULE_LICENSE ( " GPL " ) ;