2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-12-03 22:41:21 +03:00
/*
* Driver for the Epson RTC module RX - 8010 SJ
*
* Copyright ( C ) Timesys Corporation 2015
* Copyright ( C ) General Electric Company 2015
*/
# include <linux/bcd.h>
# include <linux/bitops.h>
# include <linux/i2c.h>
# include <linux/kernel.h>
# include <linux/module.h>
2020-09-14 18:46:00 +03:00
# include <linux/regmap.h>
2015-12-03 22:41:21 +03:00
# include <linux/rtc.h>
2020-09-14 18:45:52 +03:00
# define RX8010_SEC 0x10
# define RX8010_MIN 0x11
# define RX8010_HOUR 0x12
# define RX8010_WDAY 0x13
# define RX8010_MDAY 0x14
# define RX8010_MONTH 0x15
# define RX8010_YEAR 0x16
# define RX8010_RESV17 0x17
# define RX8010_ALMIN 0x18
# define RX8010_ALHOUR 0x19
# define RX8010_ALWDAY 0x1A
# define RX8010_TCOUNT0 0x1B
# define RX8010_TCOUNT1 0x1C
# define RX8010_EXT 0x1D
# define RX8010_FLAG 0x1E
# define RX8010_CTRL 0x1F
2015-12-03 22:41:21 +03:00
/* 0x20 to 0x2F are user registers */
2020-09-14 18:45:52 +03:00
# define RX8010_RESV30 0x30
# define RX8010_RESV31 0x31
# define RX8010_IRQ 0x32
2015-12-03 22:41:21 +03:00
2020-09-14 18:45:52 +03:00
# define RX8010_EXT_WADA BIT(3)
2015-12-03 22:41:21 +03:00
2020-09-14 18:45:52 +03:00
# define RX8010_FLAG_VLF BIT(1)
# define RX8010_FLAG_AF BIT(3)
# define RX8010_FLAG_TF BIT(4)
# define RX8010_FLAG_UF BIT(5)
2015-12-03 22:41:21 +03:00
2020-09-14 18:45:52 +03:00
# define RX8010_CTRL_AIE BIT(3)
# define RX8010_CTRL_UIE BIT(5)
# define RX8010_CTRL_STOP BIT(6)
# define RX8010_CTRL_TEST BIT(7)
2015-12-03 22:41:21 +03:00
2020-09-14 18:45:52 +03:00
# define RX8010_ALARM_AE BIT(7)
2015-12-03 22:41:21 +03:00
static const struct i2c_device_id rx8010_id [ ] = {
{ " rx8010 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , rx8010_id ) ;
2021-02-02 14:22:15 +03:00
static const __maybe_unused struct of_device_id rx8010_of_match [ ] = {
2017-03-03 17:29:16 +03:00
{ . compatible = " epson,rx8010 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , rx8010_of_match ) ;
2015-12-03 22:41:21 +03:00
struct rx8010_data {
2020-09-14 18:46:00 +03:00
struct regmap * regs ;
2015-12-03 22:41:21 +03:00
struct rtc_device * rtc ;
u8 ctrlreg ;
} ;
static irqreturn_t rx8010_irq_1_handler ( int irq , void * dev_id )
{
struct i2c_client * client = dev_id ;
struct rx8010_data * rx8010 = i2c_get_clientdata ( client ) ;
2020-09-14 18:46:00 +03:00
int flagreg , err ;
2015-12-03 22:41:21 +03:00
2021-01-20 01:06:50 +03:00
rtc_lock ( rx8010 - > rtc ) ;
2015-12-03 22:41:21 +03:00
2020-09-14 18:46:00 +03:00
err = regmap_read ( rx8010 - > regs , RX8010_FLAG , & flagreg ) ;
if ( err ) {
2021-01-20 01:06:50 +03:00
rtc_unlock ( rx8010 - > rtc ) ;
2015-12-03 22:41:21 +03:00
return IRQ_NONE ;
}
if ( flagreg & RX8010_FLAG_VLF )
dev_warn ( & client - > dev , " Frequency stop detected \n " ) ;
if ( flagreg & RX8010_FLAG_TF ) {
flagreg & = ~ RX8010_FLAG_TF ;
rtc_update_irq ( rx8010 - > rtc , 1 , RTC_PF | RTC_IRQF ) ;
}
if ( flagreg & RX8010_FLAG_AF ) {
flagreg & = ~ RX8010_FLAG_AF ;
rtc_update_irq ( rx8010 - > rtc , 1 , RTC_AF | RTC_IRQF ) ;
}
if ( flagreg & RX8010_FLAG_UF ) {
flagreg & = ~ RX8010_FLAG_UF ;
rtc_update_irq ( rx8010 - > rtc , 1 , RTC_UF | RTC_IRQF ) ;
}
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_FLAG , flagreg ) ;
2021-01-20 01:06:50 +03:00
rtc_unlock ( rx8010 - > rtc ) ;
2020-09-14 18:46:00 +03:00
return err ? IRQ_NONE : IRQ_HANDLED ;
2015-12-03 22:41:21 +03:00
}
static int rx8010_get_time ( struct device * dev , struct rtc_time * dt )
{
struct rx8010_data * rx8010 = dev_get_drvdata ( dev ) ;
2020-09-14 18:45:54 +03:00
u8 date [ RX8010_YEAR - RX8010_SEC + 1 ] ;
2020-09-14 18:45:51 +03:00
int flagreg , err ;
2015-12-03 22:41:21 +03:00
2020-09-14 18:46:00 +03:00
err = regmap_read ( rx8010 - > regs , RX8010_FLAG , & flagreg ) ;
if ( err )
return err ;
2015-12-03 22:41:21 +03:00
if ( flagreg & RX8010_FLAG_VLF ) {
dev_warn ( dev , " Frequency stop detected \n " ) ;
return - EINVAL ;
}
2020-09-14 18:46:00 +03:00
err = regmap_bulk_read ( rx8010 - > regs , RX8010_SEC , date , sizeof ( date ) ) ;
if ( err )
return err ;
2015-12-03 22:41:21 +03:00
dt - > tm_sec = bcd2bin ( date [ RX8010_SEC - RX8010_SEC ] & 0x7f ) ;
dt - > tm_min = bcd2bin ( date [ RX8010_MIN - RX8010_SEC ] & 0x7f ) ;
dt - > tm_hour = bcd2bin ( date [ RX8010_HOUR - RX8010_SEC ] & 0x3f ) ;
dt - > tm_mday = bcd2bin ( date [ RX8010_MDAY - RX8010_SEC ] & 0x3f ) ;
dt - > tm_mon = bcd2bin ( date [ RX8010_MONTH - RX8010_SEC ] & 0x1f ) - 1 ;
dt - > tm_year = bcd2bin ( date [ RX8010_YEAR - RX8010_SEC ] ) + 100 ;
dt - > tm_wday = ffs ( date [ RX8010_WDAY - RX8010_SEC ] & 0x7f ) ;
2018-02-19 18:23:56 +03:00
return 0 ;
2015-12-03 22:41:21 +03:00
}
static int rx8010_set_time ( struct device * dev , struct rtc_time * dt )
{
struct rx8010_data * rx8010 = dev_get_drvdata ( dev ) ;
2020-09-14 18:45:54 +03:00
u8 date [ RX8010_YEAR - RX8010_SEC + 1 ] ;
2020-09-14 18:46:00 +03:00
int err ;
2015-12-03 22:41:21 +03:00
/* set STOP bit before changing clock/calendar */
2020-09-14 18:46:00 +03:00
err = regmap_set_bits ( rx8010 - > regs , RX8010_CTRL , RX8010_CTRL_STOP ) ;
if ( err )
2020-09-14 18:45:53 +03:00
return err ;
2015-12-03 22:41:21 +03:00
date [ RX8010_SEC - RX8010_SEC ] = bin2bcd ( dt - > tm_sec ) ;
date [ RX8010_MIN - RX8010_SEC ] = bin2bcd ( dt - > tm_min ) ;
date [ RX8010_HOUR - RX8010_SEC ] = bin2bcd ( dt - > tm_hour ) ;
date [ RX8010_MDAY - RX8010_SEC ] = bin2bcd ( dt - > tm_mday ) ;
date [ RX8010_MONTH - RX8010_SEC ] = bin2bcd ( dt - > tm_mon + 1 ) ;
date [ RX8010_YEAR - RX8010_SEC ] = bin2bcd ( dt - > tm_year - 100 ) ;
date [ RX8010_WDAY - RX8010_SEC ] = bin2bcd ( 1 < < dt - > tm_wday ) ;
2020-09-14 18:46:00 +03:00
err = regmap_bulk_write ( rx8010 - > regs , RX8010_SEC , date , sizeof ( date ) ) ;
if ( err )
2020-09-14 18:45:53 +03:00
return err ;
2015-12-03 22:41:21 +03:00
/* clear STOP bit after changing clock/calendar */
2020-09-14 18:46:00 +03:00
err = regmap_clear_bits ( rx8010 - > regs , RX8010_CTRL , RX8010_CTRL_STOP ) ;
if ( err )
2020-09-14 18:45:53 +03:00
return err ;
2015-12-03 22:41:21 +03:00
2020-09-14 18:46:00 +03:00
err = regmap_clear_bits ( rx8010 - > regs , RX8010_FLAG , RX8010_FLAG_VLF ) ;
if ( err )
return err ;
2015-12-03 22:41:21 +03:00
return 0 ;
}
2020-09-17 14:46:56 +03:00
static int rx8010_init ( struct device * dev )
2015-12-03 22:41:21 +03:00
{
2020-09-14 18:46:00 +03:00
struct rx8010_data * rx8010 = dev_get_drvdata ( dev ) ;
2015-12-03 22:41:21 +03:00
u8 ctrl [ 2 ] ;
2020-09-14 18:45:55 +03:00
int need_clear = 0 , err ;
2015-12-03 22:41:21 +03:00
/* Initialize reserved registers as specified in datasheet */
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_RESV17 , 0xD8 ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_RESV30 , 0x00 ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_RESV31 , 0x08 ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_IRQ , 0x00 ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
2020-09-14 18:46:00 +03:00
err = regmap_bulk_read ( rx8010 - > regs , RX8010_FLAG , ctrl , 2 ) ;
if ( err )
return err ;
2015-12-03 22:41:21 +03:00
if ( ctrl [ 0 ] & RX8010_FLAG_VLF )
2020-09-14 18:46:00 +03:00
dev_warn ( dev , " Frequency stop was detected \n " ) ;
2015-12-03 22:41:21 +03:00
if ( ctrl [ 0 ] & RX8010_FLAG_AF ) {
2020-09-14 18:46:00 +03:00
dev_warn ( dev , " Alarm was detected \n " ) ;
2015-12-03 22:41:21 +03:00
need_clear = 1 ;
}
if ( ctrl [ 0 ] & RX8010_FLAG_TF )
need_clear = 1 ;
if ( ctrl [ 0 ] & RX8010_FLAG_UF )
need_clear = 1 ;
if ( need_clear ) {
ctrl [ 0 ] & = ~ ( RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF ) ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_FLAG , ctrl [ 0 ] ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
}
rx8010 - > ctrlreg = ( ctrl [ 1 ] & ~ RX8010_CTRL_TEST ) ;
2017-11-08 22:58:14 +03:00
return 0 ;
2015-12-03 22:41:21 +03:00
}
static int rx8010_read_alarm ( struct device * dev , struct rtc_wkalrm * t )
{
struct rx8010_data * rx8010 = dev_get_drvdata ( dev ) ;
u8 alarmvals [ 3 ] ;
2020-09-14 18:45:51 +03:00
int flagreg , err ;
2015-12-03 22:41:21 +03:00
2020-09-14 18:46:00 +03:00
err = regmap_bulk_read ( rx8010 - > regs , RX8010_ALMIN , alarmvals , 3 ) ;
if ( err )
return err ;
2015-12-03 22:41:21 +03:00
2020-09-14 18:46:00 +03:00
err = regmap_read ( rx8010 - > regs , RX8010_FLAG , & flagreg ) ;
if ( err )
return err ;
2015-12-03 22:41:21 +03:00
t - > time . tm_sec = 0 ;
t - > time . tm_min = bcd2bin ( alarmvals [ 0 ] & 0x7f ) ;
t - > time . tm_hour = bcd2bin ( alarmvals [ 1 ] & 0x3f ) ;
2016-06-28 11:43:45 +03:00
if ( ! ( alarmvals [ 2 ] & RX8010_ALARM_AE ) )
2015-12-03 22:41:21 +03:00
t - > time . tm_mday = bcd2bin ( alarmvals [ 2 ] & 0x7f ) ;
t - > enabled = ! ! ( rx8010 - > ctrlreg & RX8010_CTRL_AIE ) ;
t - > pending = ( flagreg & RX8010_FLAG_AF ) & & t - > enabled ;
2017-11-08 22:58:14 +03:00
return 0 ;
2015-12-03 22:41:21 +03:00
}
static int rx8010_set_alarm ( struct device * dev , struct rtc_wkalrm * t )
{
struct rx8010_data * rx8010 = dev_get_drvdata ( dev ) ;
u8 alarmvals [ 3 ] ;
2020-09-14 18:46:00 +03:00
int err ;
2015-12-03 22:41:21 +03:00
if ( rx8010 - > ctrlreg & ( RX8010_CTRL_AIE | RX8010_CTRL_UIE ) ) {
rx8010 - > ctrlreg & = ~ ( RX8010_CTRL_AIE | RX8010_CTRL_UIE ) ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_CTRL , rx8010 - > ctrlreg ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
}
2020-09-14 18:46:00 +03:00
err = regmap_clear_bits ( rx8010 - > regs , RX8010_FLAG , RX8010_FLAG_AF ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
alarmvals [ 0 ] = bin2bcd ( t - > time . tm_min ) ;
alarmvals [ 1 ] = bin2bcd ( t - > time . tm_hour ) ;
alarmvals [ 2 ] = bin2bcd ( t - > time . tm_mday ) ;
2020-09-14 18:46:00 +03:00
err = regmap_bulk_write ( rx8010 - > regs , RX8010_ALMIN , alarmvals , 2 ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
2020-09-14 18:46:00 +03:00
err = regmap_clear_bits ( rx8010 - > regs , RX8010_EXT , RX8010_EXT_WADA ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
if ( alarmvals [ 2 ] = = 0 )
alarmvals [ 2 ] | = RX8010_ALARM_AE ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_ALWDAY , alarmvals [ 2 ] ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
if ( t - > enabled ) {
if ( rx8010 - > rtc - > uie_rtctimer . enabled )
rx8010 - > ctrlreg | = RX8010_CTRL_UIE ;
if ( rx8010 - > rtc - > aie_timer . enabled )
rx8010 - > ctrlreg | =
( RX8010_CTRL_AIE | RX8010_CTRL_UIE ) ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_CTRL , rx8010 - > ctrlreg ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
}
return 0 ;
}
static int rx8010_alarm_irq_enable ( struct device * dev ,
unsigned int enabled )
{
struct rx8010_data * rx8010 = dev_get_drvdata ( dev ) ;
2020-09-14 18:46:00 +03:00
int err ;
2015-12-03 22:41:21 +03:00
u8 ctrl ;
ctrl = rx8010 - > ctrlreg ;
if ( enabled ) {
if ( rx8010 - > rtc - > uie_rtctimer . enabled )
ctrl | = RX8010_CTRL_UIE ;
if ( rx8010 - > rtc - > aie_timer . enabled )
ctrl | = ( RX8010_CTRL_AIE | RX8010_CTRL_UIE ) ;
} else {
if ( ! rx8010 - > rtc - > uie_rtctimer . enabled )
ctrl & = ~ RX8010_CTRL_UIE ;
if ( ! rx8010 - > rtc - > aie_timer . enabled )
ctrl & = ~ RX8010_CTRL_AIE ;
}
2020-09-14 18:46:00 +03:00
err = regmap_clear_bits ( rx8010 - > regs , RX8010_FLAG , RX8010_FLAG_AF ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
if ( ctrl ! = rx8010 - > ctrlreg ) {
rx8010 - > ctrlreg = ctrl ;
2020-09-14 18:46:00 +03:00
err = regmap_write ( rx8010 - > regs , RX8010_CTRL , rx8010 - > ctrlreg ) ;
if ( err )
2015-12-03 22:41:21 +03:00
return err ;
}
return 0 ;
}
static int rx8010_ioctl ( struct device * dev , unsigned int cmd , unsigned long arg )
{
struct rx8010_data * rx8010 = dev_get_drvdata ( dev ) ;
2020-09-14 18:46:00 +03:00
int tmp , flagreg , err ;
2015-12-03 22:41:21 +03:00
switch ( cmd ) {
case RTC_VL_READ :
2020-09-14 18:46:00 +03:00
err = regmap_read ( rx8010 - > regs , RX8010_FLAG , & flagreg ) ;
if ( err )
return err ;
2015-12-03 22:41:21 +03:00
2019-12-15 01:02:59 +03:00
tmp = flagreg & RX8010_FLAG_VLF ? RTC_VL_DATA_INVALID : 0 ;
return put_user ( tmp , ( unsigned int __user * ) arg ) ;
2015-12-03 22:41:21 +03:00
default :
return - ENOIOCTLCMD ;
}
}
2021-01-11 02:17:44 +03:00
static const struct rtc_class_ops rx8010_rtc_ops = {
2020-09-14 18:45:48 +03:00
. read_time = rx8010_get_time ,
. set_time = rx8010_set_time ,
. ioctl = rx8010_ioctl ,
. read_alarm = rx8010_read_alarm ,
. set_alarm = rx8010_set_alarm ,
. alarm_irq_enable = rx8010_alarm_irq_enable ,
} ;
2020-09-14 18:46:00 +03:00
static const struct regmap_config rx8010_regmap_config = {
. name = " rx8010-rtc " ,
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
2020-09-14 18:45:59 +03:00
static int rx8010_probe ( struct i2c_client * client )
2015-12-03 22:41:21 +03:00
{
2020-09-14 18:45:56 +03:00
struct device * dev = & client - > dev ;
2015-12-03 22:41:21 +03:00
struct rx8010_data * rx8010 ;
int err = 0 ;
2020-09-14 18:45:57 +03:00
rx8010 = devm_kzalloc ( dev , sizeof ( * rx8010 ) , GFP_KERNEL ) ;
2015-12-03 22:41:21 +03:00
if ( ! rx8010 )
return - ENOMEM ;
i2c_set_clientdata ( client , rx8010 ) ;
2020-09-14 18:46:00 +03:00
rx8010 - > regs = devm_regmap_init_i2c ( client , & rx8010_regmap_config ) ;
if ( IS_ERR ( rx8010 - > regs ) )
return PTR_ERR ( rx8010 - > regs ) ;
2020-09-17 14:46:56 +03:00
err = rx8010_init ( dev ) ;
2015-12-03 22:41:21 +03:00
if ( err )
return err ;
2020-09-14 18:45:58 +03:00
rx8010 - > rtc = devm_rtc_allocate_device ( dev ) ;
if ( IS_ERR ( rx8010 - > rtc ) )
return PTR_ERR ( rx8010 - > rtc ) ;
2015-12-03 22:41:21 +03:00
if ( client - > irq > 0 ) {
2020-09-14 18:45:56 +03:00
dev_info ( dev , " IRQ %d supplied \n " , client - > irq ) ;
err = devm_request_threaded_irq ( dev , client - > irq , NULL ,
2015-12-03 22:41:21 +03:00
rx8010_irq_1_handler ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
" rx8010 " , client ) ;
if ( err ) {
2020-09-14 18:45:56 +03:00
dev_err ( dev , " unable to request IRQ \n " ) ;
2020-09-14 18:45:48 +03:00
return err ;
2015-12-03 22:41:21 +03:00
}
2020-09-14 18:45:48 +03:00
} else {
2021-01-11 02:17:44 +03:00
clear_bit ( RTC_FEATURE_ALARM , rx8010 - > rtc - > features ) ;
2015-12-03 22:41:21 +03:00
}
2021-01-11 02:17:44 +03:00
rx8010 - > rtc - > ops = & rx8010_rtc_ops ;
2015-12-03 22:41:21 +03:00
rx8010 - > rtc - > max_user_freq = 1 ;
2020-09-14 18:46:01 +03:00
rx8010 - > rtc - > range_min = RTC_TIMESTAMP_BEGIN_2000 ;
rx8010 - > rtc - > range_max = RTC_TIMESTAMP_END_2099 ;
2015-12-03 22:41:21 +03:00
2020-11-09 19:34:08 +03:00
return devm_rtc_register_device ( rx8010 - > rtc ) ;
2015-12-03 22:41:21 +03:00
}
static struct i2c_driver rx8010_driver = {
. driver = {
. name = " rtc-rx8010 " ,
2017-03-03 17:29:16 +03:00
. of_match_table = of_match_ptr ( rx8010_of_match ) ,
2015-12-03 22:41:21 +03:00
} ,
2020-09-14 18:45:59 +03:00
. probe_new = rx8010_probe ,
2015-12-03 22:41:21 +03:00
. id_table = rx8010_id ,
} ;
module_i2c_driver ( rx8010_driver ) ;
MODULE_AUTHOR ( " Akshay Bhat <akshay.bhat@timesys.com> " ) ;
MODULE_DESCRIPTION ( " Epson RX8010SJ RTC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;