2018-08-07 19:19:19 +03:00
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2013-2014 Samsung Electronics Co., Ltd
// http://www.samsung.com
//
// Copyright (C) 2013 Google, Inc
2013-11-13 03:11:04 +04:00
2015-04-16 22:46:14 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2013-11-13 03:11:04 +04:00
# include <linux/module.h>
# include <linux/i2c.h>
# include <linux/bcd.h>
# include <linux/regmap.h>
# include <linux/rtc.h>
# include <linux/platform_device.h>
# include <linux/mfd/samsung/core.h>
# include <linux/mfd/samsung/irq.h>
# include <linux/mfd/samsung/rtc.h>
2014-06-11 02:18:46 +04:00
# include <linux/mfd/samsung/s2mps14.h>
2013-11-13 03:11:04 +04:00
2013-12-13 05:12:28 +04:00
/*
* Maximum number of retries for checking changes in UDR field
2014-06-11 02:18:40 +04:00
* of S5M_RTC_UDR_CON register ( to limit possible endless loop ) .
2013-12-13 05:12:28 +04:00
*
* After writing to RTC registers ( setting time or alarm ) read the UDR field
2014-06-11 02:18:40 +04:00
* in S5M_RTC_UDR_CON register . UDR is auto - cleared when data have
2013-12-13 05:12:28 +04:00
* been transferred .
*/
# define UDR_READ_RETRY_CNT 5
2018-03-10 09:27:15 +03:00
enum {
RTC_SEC = 0 ,
RTC_MIN ,
RTC_HOUR ,
RTC_WEEKDAY ,
RTC_DATE ,
RTC_MONTH ,
RTC_YEAR1 ,
RTC_YEAR2 ,
2018-03-10 09:27:35 +03:00
/* Make sure this is always the last enum name. */
RTC_MAX_NUM_TIME_REGS
2018-03-10 09:27:15 +03:00
} ;
2015-12-30 07:47:27 +03:00
/*
* Registers used by the driver which are different between chipsets .
*
* Operations like read time and write alarm / time require updating
* specific fields in UDR register . These fields usually are auto - cleared
* ( with some exceptions ) .
*
* Table of operations per device :
*
* Device | Write time | Read time | Write alarm
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* S5M8767 | UDR + TIME | | UDR
* S2MPS11 / 14 | WUDR | RUDR | WUDR + RUDR
* S2MPS13 | WUDR | RUDR | WUDR + AUDR
* S2MPS15 | WUDR | RUDR | AUDR
*/
2014-06-11 02:18:44 +04:00
struct s5m_rtc_reg_config {
/* Number of registers used for setting time/alarm0/alarm1 */
unsigned int regs_count ;
/* First register for time, seconds */
unsigned int time ;
/* RTC control register */
unsigned int ctrl ;
/* First register for alarm 0, seconds */
unsigned int alarm0 ;
/* First register for alarm 1, seconds */
unsigned int alarm1 ;
/*
* Register for update flag ( UDR ) . Typically setting UDR field to 1
* will enable update of time or alarm register . Then it will be
* auto - cleared after successful update .
*/
2015-12-30 07:47:25 +03:00
unsigned int udr_update ;
2015-12-30 07:47:26 +03:00
/* Auto-cleared mask in UDR field for writing time and alarm */
unsigned int autoclear_udr_mask ;
2015-12-30 07:47:27 +03:00
/*
* Masks in UDR field for time and alarm operations .
* The read time mask can be 0. Rest should not .
*/
unsigned int read_time_udr_mask ;
unsigned int write_time_udr_mask ;
unsigned int write_alarm_udr_mask ;
2014-06-11 02:18:44 +04:00
} ;
/* Register map for S5M8763 and S5M8767 */
static const struct s5m_rtc_reg_config s5m_rtc_regs = {
. regs_count = 8 ,
. time = S5M_RTC_SEC ,
. ctrl = S5M_ALARM1_CONF ,
. alarm0 = S5M_ALARM0_SEC ,
. alarm1 = S5M_ALARM1_SEC ,
2015-12-30 07:47:25 +03:00
. udr_update = S5M_RTC_UDR_CON ,
2015-12-30 07:47:26 +03:00
. autoclear_udr_mask = S5M_RTC_UDR_MASK ,
2015-12-30 07:47:27 +03:00
. read_time_udr_mask = 0 , /* Not needed */
. write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK ,
. write_alarm_udr_mask = S5M_RTC_UDR_MASK ,
} ;
/* Register map for S2MPS13 */
static const struct s5m_rtc_reg_config s2mps13_rtc_regs = {
. regs_count = 7 ,
. time = S2MPS_RTC_SEC ,
. ctrl = S2MPS_RTC_CTRL ,
. alarm0 = S2MPS_ALARM0_SEC ,
. alarm1 = S2MPS_ALARM1_SEC ,
. udr_update = S2MPS_RTC_UDR_CON ,
. autoclear_udr_mask = S2MPS_RTC_WUDR_MASK ,
. read_time_udr_mask = S2MPS_RTC_RUDR_MASK ,
. write_time_udr_mask = S2MPS_RTC_WUDR_MASK ,
. write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK ,
} ;
/* Register map for S2MPS11/14 */
static const struct s5m_rtc_reg_config s2mps14_rtc_regs = {
. regs_count = 7 ,
. time = S2MPS_RTC_SEC ,
. ctrl = S2MPS_RTC_CTRL ,
. alarm0 = S2MPS_ALARM0_SEC ,
. alarm1 = S2MPS_ALARM1_SEC ,
. udr_update = S2MPS_RTC_UDR_CON ,
. autoclear_udr_mask = S2MPS_RTC_WUDR_MASK ,
. read_time_udr_mask = S2MPS_RTC_RUDR_MASK ,
. write_time_udr_mask = S2MPS_RTC_WUDR_MASK ,
. write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK ,
2014-06-11 02:18:44 +04:00
} ;
2014-06-11 02:18:46 +04:00
/*
2015-12-30 07:47:27 +03:00
* Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits
* are swapped .
2014-06-11 02:18:46 +04:00
*/
2015-12-30 07:47:27 +03:00
static const struct s5m_rtc_reg_config s2mps15_rtc_regs = {
2014-06-11 02:18:46 +04:00
. regs_count = 7 ,
. time = S2MPS_RTC_SEC ,
. ctrl = S2MPS_RTC_CTRL ,
. alarm0 = S2MPS_ALARM0_SEC ,
. alarm1 = S2MPS_ALARM1_SEC ,
2015-12-30 07:47:25 +03:00
. udr_update = S2MPS_RTC_UDR_CON ,
2015-12-30 07:47:26 +03:00
. autoclear_udr_mask = S2MPS_RTC_WUDR_MASK ,
2015-12-30 07:47:27 +03:00
. read_time_udr_mask = S2MPS_RTC_RUDR_MASK ,
. write_time_udr_mask = S2MPS15_RTC_WUDR_MASK ,
. write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK ,
2014-06-11 02:18:46 +04:00
} ;
2013-11-13 03:11:04 +04:00
struct s5m_rtc_info {
struct device * dev ;
2014-04-14 11:40:45 +04:00
struct i2c_client * i2c ;
2013-11-13 03:11:04 +04:00
struct sec_pmic_dev * s5m87xx ;
2013-12-13 05:12:25 +04:00
struct regmap * regmap ;
2013-11-13 03:11:04 +04:00
struct rtc_device * rtc_dev ;
int irq ;
2015-04-16 22:49:27 +03:00
enum sec_device_type device_type ;
2013-11-13 03:11:04 +04:00
int rtc_24hr_mode ;
2014-06-11 02:18:44 +04:00
const struct s5m_rtc_reg_config * regs ;
2013-11-13 03:11:04 +04:00
} ;
2014-04-14 11:40:45 +04:00
static const struct regmap_config s5m_rtc_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
2014-06-11 02:18:40 +04:00
. max_register = S5M_RTC_REG_MAX ,
2014-04-14 11:40:45 +04:00
} ;
static const struct regmap_config s2mps14_rtc_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = S2MPS_RTC_REG_MAX ,
} ;
2013-11-13 03:11:04 +04:00
static void s5m8767_data_to_tm ( u8 * data , struct rtc_time * tm ,
int rtc_24hr_mode )
{
tm - > tm_sec = data [ RTC_SEC ] & 0x7f ;
tm - > tm_min = data [ RTC_MIN ] & 0x7f ;
if ( rtc_24hr_mode ) {
tm - > tm_hour = data [ RTC_HOUR ] & 0x1f ;
} else {
tm - > tm_hour = data [ RTC_HOUR ] & 0x0f ;
if ( data [ RTC_HOUR ] & HOUR_PM_MASK )
tm - > tm_hour + = 12 ;
}
tm - > tm_wday = ffs ( data [ RTC_WEEKDAY ] & 0x7f ) ;
tm - > tm_mday = data [ RTC_DATE ] & 0x1f ;
tm - > tm_mon = ( data [ RTC_MONTH ] & 0x0f ) - 1 ;
tm - > tm_year = ( data [ RTC_YEAR1 ] & 0x7f ) + 100 ;
tm - > tm_yday = 0 ;
tm - > tm_isdst = 0 ;
}
static int s5m8767_tm_to_data ( struct rtc_time * tm , u8 * data )
{
data [ RTC_SEC ] = tm - > tm_sec ;
data [ RTC_MIN ] = tm - > tm_min ;
if ( tm - > tm_hour > = 12 )
data [ RTC_HOUR ] = tm - > tm_hour | HOUR_PM_MASK ;
else
data [ RTC_HOUR ] = tm - > tm_hour & ~ HOUR_PM_MASK ;
data [ RTC_WEEKDAY ] = 1 < < tm - > tm_wday ;
data [ RTC_DATE ] = tm - > tm_mday ;
data [ RTC_MONTH ] = tm - > tm_mon + 1 ;
2021-08-04 13:41:32 +03:00
data [ RTC_YEAR1 ] = tm - > tm_year - 100 ;
2013-11-13 03:11:04 +04:00
2021-08-04 13:41:32 +03:00
return 0 ;
2013-11-13 03:11:04 +04:00
}
2013-12-13 05:12:28 +04:00
/*
* Read RTC_UDR_CON register and wait till UDR field is cleared .
* This indicates that time / alarm update ended .
*/
2016-02-16 05:04:42 +03:00
static int s5m8767_wait_for_udr_update ( struct s5m_rtc_info * info )
2013-12-13 05:12:28 +04:00
{
int ret , retry = UDR_READ_RETRY_CNT ;
unsigned int data ;
do {
2015-12-30 07:47:25 +03:00
ret = regmap_read ( info - > regmap , info - > regs - > udr_update , & data ) ;
2015-12-30 07:47:26 +03:00
} while ( - - retry & & ( data & info - > regs - > autoclear_udr_mask ) & & ! ret ) ;
2013-12-13 05:12:28 +04:00
if ( ! retry )
dev_err ( info - > dev , " waiting for UDR update, reached max number of retries \n " ) ;
return ret ;
}
2016-02-16 05:04:42 +03:00
static int s5m_check_peding_alarm_interrupt ( struct s5m_rtc_info * info ,
2014-06-11 02:18:44 +04:00
struct rtc_wkalrm * alarm )
{
int ret ;
unsigned int val ;
switch ( info - > device_type ) {
case S5M8767X :
case S5M8763X :
ret = regmap_read ( info - > regmap , S5M_RTC_STATUS , & val ) ;
val & = S5M_ALARM0_STATUS ;
break ;
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2014-06-11 02:18:46 +04:00
ret = regmap_read ( info - > s5m87xx - > regmap_pmic , S2MPS14_REG_ST2 ,
& val ) ;
val & = S2MPS_ALARM0_STATUS ;
break ;
2014-06-11 02:18:44 +04:00
default :
return - EINVAL ;
}
if ( ret < 0 )
return ret ;
if ( val )
alarm - > pending = 1 ;
else
alarm - > pending = 0 ;
return 0 ;
}
2016-02-16 05:04:42 +03:00
static int s5m8767_rtc_set_time_reg ( struct s5m_rtc_info * info )
2013-11-13 03:11:04 +04:00
{
int ret ;
unsigned int data ;
2015-12-30 07:47:25 +03:00
ret = regmap_read ( info - > regmap , info - > regs - > udr_update , & data ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 ) {
dev_err ( info - > dev , " failed to read update reg(%d) \n " , ret ) ;
return ret ;
}
2015-12-30 07:47:27 +03:00
data | = info - > regs - > write_time_udr_mask ;
2015-11-20 13:37:53 +03:00
2015-12-30 07:47:25 +03:00
ret = regmap_write ( info - > regmap , info - > regs - > udr_update , data ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 ) {
dev_err ( info - > dev , " failed to write update reg(%d) \n " , ret ) ;
return ret ;
}
2013-12-13 05:12:28 +04:00
ret = s5m8767_wait_for_udr_update ( info ) ;
2013-11-13 03:11:04 +04:00
return ret ;
}
2016-02-16 05:04:42 +03:00
static int s5m8767_rtc_set_alarm_reg ( struct s5m_rtc_info * info )
2013-11-13 03:11:04 +04:00
{
int ret ;
unsigned int data ;
2015-12-30 07:47:25 +03:00
ret = regmap_read ( info - > regmap , info - > regs - > udr_update , & data ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 ) {
dev_err ( info - > dev , " %s: fail to read update reg(%d) \n " ,
__func__ , ret ) ;
return ret ;
}
2015-12-30 07:47:27 +03:00
data | = info - > regs - > write_alarm_udr_mask ;
2014-06-11 02:18:46 +04:00
switch ( info - > device_type ) {
case S5M8763X :
case S5M8767X :
data & = ~ S5M_RTC_TIME_EN_MASK ;
break ;
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2015-12-30 07:47:27 +03:00
/* No exceptions needed */
2015-04-16 22:45:45 +03:00
break ;
2014-06-11 02:18:46 +04:00
default :
return - EINVAL ;
}
2013-11-13 03:11:04 +04:00
2015-12-30 07:47:25 +03:00
ret = regmap_write ( info - > regmap , info - > regs - > udr_update , data ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 ) {
dev_err ( info - > dev , " %s: fail to write update reg(%d) \n " ,
__func__ , ret ) ;
return ret ;
}
2013-12-13 05:12:28 +04:00
ret = s5m8767_wait_for_udr_update ( info ) ;
2013-11-13 03:11:04 +04:00
2015-04-16 22:45:45 +03:00
/* On S2MPS13 the AUDR is not auto-cleared */
if ( info - > device_type = = S2MPS13X )
2015-12-30 07:47:25 +03:00
regmap_update_bits ( info - > regmap , info - > regs - > udr_update ,
2015-04-16 22:45:45 +03:00
S2MPS13_RTC_AUDR_MASK , 0 ) ;
2013-11-13 03:11:04 +04:00
return ret ;
}
static void s5m8763_data_to_tm ( u8 * data , struct rtc_time * tm )
{
tm - > tm_sec = bcd2bin ( data [ RTC_SEC ] ) ;
tm - > tm_min = bcd2bin ( data [ RTC_MIN ] ) ;
if ( data [ RTC_HOUR ] & HOUR_12 ) {
tm - > tm_hour = bcd2bin ( data [ RTC_HOUR ] & 0x1f ) ;
if ( data [ RTC_HOUR ] & HOUR_PM )
tm - > tm_hour + = 12 ;
} else {
tm - > tm_hour = bcd2bin ( data [ RTC_HOUR ] & 0x3f ) ;
}
tm - > tm_wday = data [ RTC_WEEKDAY ] & 0x07 ;
tm - > tm_mday = bcd2bin ( data [ RTC_DATE ] ) ;
tm - > tm_mon = bcd2bin ( data [ RTC_MONTH ] ) ;
tm - > tm_year = bcd2bin ( data [ RTC_YEAR1 ] ) + bcd2bin ( data [ RTC_YEAR2 ] ) * 100 ;
tm - > tm_year - = 1900 ;
}
static void s5m8763_tm_to_data ( struct rtc_time * tm , u8 * data )
{
data [ RTC_SEC ] = bin2bcd ( tm - > tm_sec ) ;
data [ RTC_MIN ] = bin2bcd ( tm - > tm_min ) ;
data [ RTC_HOUR ] = bin2bcd ( tm - > tm_hour ) ;
data [ RTC_WEEKDAY ] = tm - > tm_wday ;
data [ RTC_DATE ] = bin2bcd ( tm - > tm_mday ) ;
data [ RTC_MONTH ] = bin2bcd ( tm - > tm_mon ) ;
data [ RTC_YEAR1 ] = bin2bcd ( tm - > tm_year % 100 ) ;
data [ RTC_YEAR2 ] = bin2bcd ( ( tm - > tm_year + 1900 ) / 100 ) ;
}
static int s5m_rtc_read_time ( struct device * dev , struct rtc_time * tm )
{
struct s5m_rtc_info * info = dev_get_drvdata ( dev ) ;
2018-03-10 09:27:35 +03:00
u8 data [ RTC_MAX_NUM_TIME_REGS ] ;
2013-11-13 03:11:04 +04:00
int ret ;
2015-12-30 07:47:27 +03:00
if ( info - > regs - > read_time_udr_mask ) {
2014-06-11 02:18:46 +04:00
ret = regmap_update_bits ( info - > regmap ,
2015-12-30 07:47:25 +03:00
info - > regs - > udr_update ,
2015-12-30 07:47:27 +03:00
info - > regs - > read_time_udr_mask ,
info - > regs - > read_time_udr_mask ) ;
2014-06-11 02:18:46 +04:00
if ( ret ) {
dev_err ( dev ,
" Failed to prepare registers for time reading: %d \n " ,
ret ) ;
return ret ;
}
}
2014-06-11 02:18:44 +04:00
ret = regmap_bulk_read ( info - > regmap , info - > regs - > time , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
switch ( info - > device_type ) {
case S5M8763X :
s5m8763_data_to_tm ( data , tm ) ;
break ;
case S5M8767X :
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2013-11-13 03:11:04 +04:00
s5m8767_data_to_tm ( data , tm , info - > rtc_24hr_mode ) ;
break ;
default :
return - EINVAL ;
}
2018-12-05 00:23:26 +03:00
dev_dbg ( dev , " %s: %ptR(%d) \n " , __func__ , tm , tm - > tm_wday ) ;
2013-11-13 03:11:04 +04:00
2018-02-19 18:23:56 +03:00
return 0 ;
2013-11-13 03:11:04 +04:00
}
static int s5m_rtc_set_time ( struct device * dev , struct rtc_time * tm )
{
struct s5m_rtc_info * info = dev_get_drvdata ( dev ) ;
2018-03-10 09:27:35 +03:00
u8 data [ RTC_MAX_NUM_TIME_REGS ] ;
2013-11-13 03:11:04 +04:00
int ret = 0 ;
switch ( info - > device_type ) {
case S5M8763X :
s5m8763_tm_to_data ( tm , data ) ;
break ;
case S5M8767X :
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2013-11-13 03:11:04 +04:00
ret = s5m8767_tm_to_data ( tm , data ) ;
break ;
default :
return - EINVAL ;
}
if ( ret < 0 )
return ret ;
2018-12-05 00:23:26 +03:00
dev_dbg ( dev , " %s: %ptR(%d) \n " , __func__ , tm , tm - > tm_wday ) ;
2013-11-13 03:11:04 +04:00
2014-06-11 02:18:44 +04:00
ret = regmap_raw_write ( info - > regmap , info - > regs - > time , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
ret = s5m8767_rtc_set_time_reg ( info ) ;
return ret ;
}
static int s5m_rtc_read_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct s5m_rtc_info * info = dev_get_drvdata ( dev ) ;
2018-03-10 09:27:35 +03:00
u8 data [ RTC_MAX_NUM_TIME_REGS ] ;
2013-11-13 03:11:04 +04:00
unsigned int val ;
int ret , i ;
2014-06-11 02:18:44 +04:00
ret = regmap_bulk_read ( info - > regmap , info - > regs - > alarm0 , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
switch ( info - > device_type ) {
case S5M8763X :
s5m8763_data_to_tm ( data , & alrm - > time ) ;
2014-06-11 02:18:40 +04:00
ret = regmap_read ( info - > regmap , S5M_ALARM0_CONF , & val ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
alrm - > enabled = ! ! val ;
break ;
case S5M8767X :
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2013-11-13 03:11:04 +04:00
s5m8767_data_to_tm ( data , & alrm - > time , info - > rtc_24hr_mode ) ;
alrm - > enabled = 0 ;
2014-06-11 02:18:44 +04:00
for ( i = 0 ; i < info - > regs - > regs_count ; i + + ) {
2013-11-13 03:11:04 +04:00
if ( data [ i ] & ALARM_ENABLE_MASK ) {
alrm - > enabled = 1 ;
break ;
}
}
break ;
default :
return - EINVAL ;
}
2018-12-05 00:23:26 +03:00
dev_dbg ( dev , " %s: %ptR(%d) \n " , __func__ , & alrm - > time , alrm - > time . tm_wday ) ;
2014-06-11 02:18:44 +04:00
2021-07-08 08:13:04 +03:00
return s5m_check_peding_alarm_interrupt ( info , alrm ) ;
2013-11-13 03:11:04 +04:00
}
static int s5m_rtc_stop_alarm ( struct s5m_rtc_info * info )
{
2018-03-10 09:27:35 +03:00
u8 data [ RTC_MAX_NUM_TIME_REGS ] ;
2013-11-13 03:11:04 +04:00
int ret , i ;
struct rtc_time tm ;
2014-06-11 02:18:44 +04:00
ret = regmap_bulk_read ( info - > regmap , info - > regs - > alarm0 , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
s5m8767_data_to_tm ( data , & tm , info - > rtc_24hr_mode ) ;
2018-12-05 00:23:26 +03:00
dev_dbg ( info - > dev , " %s: %ptR(%d) \n " , __func__ , & tm , tm . tm_wday ) ;
2013-11-13 03:11:04 +04:00
switch ( info - > device_type ) {
case S5M8763X :
2014-06-11 02:18:40 +04:00
ret = regmap_write ( info - > regmap , S5M_ALARM0_CONF , 0 ) ;
2013-11-13 03:11:04 +04:00
break ;
case S5M8767X :
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2014-06-11 02:18:44 +04:00
for ( i = 0 ; i < info - > regs - > regs_count ; i + + )
2013-11-13 03:11:04 +04:00
data [ i ] & = ~ ALARM_ENABLE_MASK ;
2014-06-11 02:18:44 +04:00
ret = regmap_raw_write ( info - > regmap , info - > regs - > alarm0 , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
ret = s5m8767_rtc_set_alarm_reg ( info ) ;
break ;
default :
return - EINVAL ;
}
return ret ;
}
static int s5m_rtc_start_alarm ( struct s5m_rtc_info * info )
{
int ret ;
2018-03-10 09:27:35 +03:00
u8 data [ RTC_MAX_NUM_TIME_REGS ] ;
2013-11-13 03:11:04 +04:00
u8 alarm0_conf ;
struct rtc_time tm ;
2014-06-11 02:18:44 +04:00
ret = regmap_bulk_read ( info - > regmap , info - > regs - > alarm0 , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
s5m8767_data_to_tm ( data , & tm , info - > rtc_24hr_mode ) ;
2018-12-05 00:23:26 +03:00
dev_dbg ( info - > dev , " %s: %ptR(%d) \n " , __func__ , & tm , tm . tm_wday ) ;
2013-11-13 03:11:04 +04:00
switch ( info - > device_type ) {
case S5M8763X :
alarm0_conf = 0x77 ;
2014-06-11 02:18:40 +04:00
ret = regmap_write ( info - > regmap , S5M_ALARM0_CONF , alarm0_conf ) ;
2013-11-13 03:11:04 +04:00
break ;
case S5M8767X :
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2013-11-13 03:11:04 +04:00
data [ RTC_SEC ] | = ALARM_ENABLE_MASK ;
data [ RTC_MIN ] | = ALARM_ENABLE_MASK ;
data [ RTC_HOUR ] | = ALARM_ENABLE_MASK ;
data [ RTC_WEEKDAY ] & = ~ ALARM_ENABLE_MASK ;
if ( data [ RTC_DATE ] & 0x1f )
data [ RTC_DATE ] | = ALARM_ENABLE_MASK ;
if ( data [ RTC_MONTH ] & 0xf )
data [ RTC_MONTH ] | = ALARM_ENABLE_MASK ;
if ( data [ RTC_YEAR1 ] & 0x7f )
data [ RTC_YEAR1 ] | = ALARM_ENABLE_MASK ;
2014-06-11 02:18:44 +04:00
ret = regmap_raw_write ( info - > regmap , info - > regs - > alarm0 , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
ret = s5m8767_rtc_set_alarm_reg ( info ) ;
break ;
default :
return - EINVAL ;
}
return ret ;
}
static int s5m_rtc_set_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct s5m_rtc_info * info = dev_get_drvdata ( dev ) ;
2018-03-10 09:27:35 +03:00
u8 data [ RTC_MAX_NUM_TIME_REGS ] ;
2013-11-13 03:11:04 +04:00
int ret ;
switch ( info - > device_type ) {
case S5M8763X :
s5m8763_tm_to_data ( & alrm - > time , data ) ;
break ;
case S5M8767X :
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2013-11-13 03:11:04 +04:00
s5m8767_tm_to_data ( & alrm - > time , data ) ;
break ;
default :
return - EINVAL ;
}
2018-12-05 00:23:26 +03:00
dev_dbg ( dev , " %s: %ptR(%d) \n " , __func__ , & alrm - > time , alrm - > time . tm_wday ) ;
2013-11-13 03:11:04 +04:00
ret = s5m_rtc_stop_alarm ( info ) ;
if ( ret < 0 )
return ret ;
2014-06-11 02:18:44 +04:00
ret = regmap_raw_write ( info - > regmap , info - > regs - > alarm0 , data ,
info - > regs - > regs_count ) ;
2013-11-13 03:11:04 +04:00
if ( ret < 0 )
return ret ;
ret = s5m8767_rtc_set_alarm_reg ( info ) ;
if ( ret < 0 )
return ret ;
if ( alrm - > enabled )
ret = s5m_rtc_start_alarm ( info ) ;
return ret ;
}
static int s5m_rtc_alarm_irq_enable ( struct device * dev ,
unsigned int enabled )
{
struct s5m_rtc_info * info = dev_get_drvdata ( dev ) ;
if ( enabled )
return s5m_rtc_start_alarm ( info ) ;
else
return s5m_rtc_stop_alarm ( info ) ;
}
static irqreturn_t s5m_rtc_alarm_irq ( int irq , void * data )
{
struct s5m_rtc_info * info = data ;
rtc_update_irq ( info - > rtc_dev , 1 , RTC_IRQF | RTC_AF ) ;
return IRQ_HANDLED ;
}
static const struct rtc_class_ops s5m_rtc_ops = {
. read_time = s5m_rtc_read_time ,
. set_time = s5m_rtc_set_time ,
. read_alarm = s5m_rtc_read_alarm ,
. set_alarm = s5m_rtc_set_alarm ,
. alarm_irq_enable = s5m_rtc_alarm_irq_enable ,
} ;
static int s5m8767_rtc_init_reg ( struct s5m_rtc_info * info )
{
u8 data [ 2 ] ;
int ret ;
2014-06-11 02:18:46 +04:00
switch ( info - > device_type ) {
case S5M8763X :
case S5M8767X :
/* UDR update time. Default of 7.32 ms is too long. */
ret = regmap_update_bits ( info - > regmap , S5M_RTC_UDR_CON ,
S5M_RTC_UDR_T_MASK , S5M_RTC_UDR_T_450_US ) ;
if ( ret < 0 )
dev_err ( info - > dev , " %s: fail to change UDR time: %d \n " ,
__func__ , ret ) ;
2014-06-11 02:18:43 +04:00
2014-06-11 02:18:46 +04:00
/* Set RTC control register : Binary mode, 24hour mode */
data [ 0 ] = ( 1 < < BCD_EN_SHIFT ) | ( 1 < < MODEL24_SHIFT ) ;
data [ 1 ] = ( 0 < < BCD_EN_SHIFT ) | ( 1 < < MODEL24_SHIFT ) ;
ret = regmap_raw_write ( info - > regmap , S5M_ALARM0_CONF , data , 2 ) ;
break ;
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2014-06-11 02:18:46 +04:00
case S2MPS14X :
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2014-06-11 02:18:46 +04:00
data [ 0 ] = ( 0 < < BCD_EN_SHIFT ) | ( 1 < < MODEL24_SHIFT ) ;
ret = regmap_write ( info - > regmap , info - > regs - > ctrl , data [ 0 ] ) ;
2015-08-21 12:43:41 +03:00
if ( ret < 0 )
break ;
/*
* Should set WUDR & ( RUDR or AUDR ) bits to high after writing
* RTC_CTRL register like writing Alarm registers . We can ' t find
* the description from datasheet but vendor code does that
* really .
*/
ret = s5m8767_rtc_set_alarm_reg ( info ) ;
2014-06-11 02:18:46 +04:00
break ;
default :
return - EINVAL ;
}
2013-11-13 03:11:04 +04:00
info - > rtc_24hr_mode = 1 ;
if ( ret < 0 ) {
dev_err ( info - > dev , " %s: fail to write controlm reg(%d) \n " ,
__func__ , ret ) ;
return ret ;
}
return ret ;
}
static int s5m_rtc_probe ( struct platform_device * pdev )
{
struct sec_pmic_dev * s5m87xx = dev_get_drvdata ( pdev - > dev . parent ) ;
struct s5m_rtc_info * info ;
2014-04-14 11:40:45 +04:00
const struct regmap_config * regmap_cfg ;
2014-06-11 02:18:47 +04:00
int ret , alarm_irq ;
2013-11-13 03:11:04 +04:00
info = devm_kzalloc ( & pdev - > dev , sizeof ( * info ) , GFP_KERNEL ) ;
if ( ! info )
return - ENOMEM ;
2015-04-16 22:49:27 +03:00
switch ( platform_get_device_id ( pdev ) - > driver_data ) {
2015-11-20 13:37:53 +03:00
case S2MPS15X :
2015-12-30 07:47:27 +03:00
regmap_cfg = & s2mps14_rtc_regmap_config ;
info - > regs = & s2mps15_rtc_regs ;
alarm_irq = S2MPS14_IRQ_RTCA0 ;
break ;
2014-04-14 11:40:45 +04:00
case S2MPS14X :
2015-12-30 07:47:27 +03:00
regmap_cfg = & s2mps14_rtc_regmap_config ;
info - > regs = & s2mps14_rtc_regs ;
alarm_irq = S2MPS14_IRQ_RTCA0 ;
break ;
2015-04-16 22:45:45 +03:00
case S2MPS13X :
2014-04-14 11:40:45 +04:00
regmap_cfg = & s2mps14_rtc_regmap_config ;
2015-12-30 07:47:27 +03:00
info - > regs = & s2mps13_rtc_regs ;
2014-06-11 02:18:47 +04:00
alarm_irq = S2MPS14_IRQ_RTCA0 ;
2014-04-14 11:40:45 +04:00
break ;
case S5M8763X :
regmap_cfg = & s5m_rtc_regmap_config ;
2014-06-11 02:18:44 +04:00
info - > regs = & s5m_rtc_regs ;
2014-06-11 02:18:47 +04:00
alarm_irq = S5M8763_IRQ_ALARM0 ;
2014-04-14 11:40:45 +04:00
break ;
case S5M8767X :
regmap_cfg = & s5m_rtc_regmap_config ;
2014-06-11 02:18:44 +04:00
info - > regs = & s5m_rtc_regs ;
2014-06-11 02:18:47 +04:00
alarm_irq = S5M8767_IRQ_RTCA1 ;
2014-04-14 11:40:45 +04:00
break ;
default :
2015-04-16 22:49:27 +03:00
dev_err ( & pdev - > dev ,
" Device type %lu is not supported by RTC driver \n " ,
platform_get_device_id ( pdev ) - > driver_data ) ;
2014-04-14 11:40:45 +04:00
return - ENODEV ;
}
2021-01-14 13:22:18 +03:00
info - > i2c = devm_i2c_new_dummy_device ( & pdev - > dev , s5m87xx - > i2c - > adapter ,
RTC_I2C_ADDR ) ;
2019-07-22 20:26:18 +03:00
if ( IS_ERR ( info - > i2c ) ) {
2014-04-14 11:40:45 +04:00
dev_err ( & pdev - > dev , " Failed to allocate I2C for RTC \n " ) ;
2019-07-22 20:26:18 +03:00
return PTR_ERR ( info - > i2c ) ;
2014-04-14 11:40:45 +04:00
}
info - > regmap = devm_regmap_init_i2c ( info - > i2c , regmap_cfg ) ;
if ( IS_ERR ( info - > regmap ) ) {
ret = PTR_ERR ( info - > regmap ) ;
dev_err ( & pdev - > dev , " Failed to allocate RTC register map: %d \n " ,
ret ) ;
2021-01-14 13:22:18 +03:00
return ret ;
2014-04-14 11:40:45 +04:00
}
2013-11-13 03:11:04 +04:00
info - > dev = & pdev - > dev ;
info - > s5m87xx = s5m87xx ;
2015-04-16 22:49:27 +03:00
info - > device_type = platform_get_device_id ( pdev ) - > driver_data ;
2013-11-13 03:11:04 +04:00
2014-08-30 02:18:53 +04:00
if ( s5m87xx - > irq_data ) {
info - > irq = regmap_irq_get_virq ( s5m87xx - > irq_data , alarm_irq ) ;
if ( info - > irq < = 0 ) {
dev_err ( & pdev - > dev , " Failed to get virtual IRQ %d \n " ,
2014-06-11 02:18:47 +04:00
alarm_irq ) ;
2021-01-14 13:22:18 +03:00
return - EINVAL ;
2014-08-30 02:18:53 +04:00
}
2013-11-13 03:11:04 +04:00
}
platform_set_drvdata ( pdev , info ) ;
ret = s5m8767_rtc_init_reg ( info ) ;
2021-01-14 13:22:19 +03:00
if ( ret )
return ret ;
2013-11-13 03:11:04 +04:00
2021-08-04 13:41:29 +03:00
info - > rtc_dev = devm_rtc_allocate_device ( & pdev - > dev ) ;
2021-01-14 13:22:18 +03:00
if ( IS_ERR ( info - > rtc_dev ) )
return PTR_ERR ( info - > rtc_dev ) ;
2013-11-13 03:11:04 +04:00
2021-08-04 13:41:29 +03:00
info - > rtc_dev - > ops = & s5m_rtc_ops ;
2021-08-04 13:41:32 +03:00
if ( info - > device_type = = S5M8763X ) {
info - > rtc_dev - > range_min = RTC_TIMESTAMP_BEGIN_0000 ;
info - > rtc_dev - > range_max = RTC_TIMESTAMP_END_9999 ;
} else {
info - > rtc_dev - > range_min = RTC_TIMESTAMP_BEGIN_2000 ;
info - > rtc_dev - > range_max = RTC_TIMESTAMP_END_2099 ;
}
2014-08-30 02:18:53 +04:00
if ( ! info - > irq ) {
2021-08-04 13:41:30 +03:00
clear_bit ( RTC_FEATURE_ALARM , info - > rtc_dev - > features ) ;
} else {
ret = devm_request_threaded_irq ( & pdev - > dev , info - > irq , NULL ,
s5m_rtc_alarm_irq , 0 , " rtc-alarm0 " ,
info ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Failed to request alarm IRQ: %d: %d \n " ,
info - > irq , ret ) ;
return ret ;
}
2021-08-04 13:41:31 +03:00
device_init_wakeup ( & pdev - > dev , 1 ) ;
2014-04-14 11:40:45 +04:00
}
2021-08-04 13:41:30 +03:00
return devm_rtc_register_device ( info - > rtc_dev ) ;
2014-04-14 11:40:45 +04:00
}
2014-01-24 03:55:19 +04:00
# ifdef CONFIG_PM_SLEEP
2013-12-13 05:12:30 +04:00
static int s5m_rtc_resume ( struct device * dev )
{
struct s5m_rtc_info * info = dev_get_drvdata ( dev ) ;
int ret = 0 ;
2014-08-30 02:18:53 +04:00
if ( info - > irq & & device_may_wakeup ( dev ) )
2013-12-13 05:12:30 +04:00
ret = disable_irq_wake ( info - > irq ) ;
return ret ;
}
static int s5m_rtc_suspend ( struct device * dev )
{
struct s5m_rtc_info * info = dev_get_drvdata ( dev ) ;
int ret = 0 ;
2014-08-30 02:18:53 +04:00
if ( info - > irq & & device_may_wakeup ( dev ) )
2013-12-13 05:12:30 +04:00
ret = enable_irq_wake ( info - > irq ) ;
return ret ;
}
2014-01-24 03:55:19 +04:00
# endif /* CONFIG_PM_SLEEP */
2013-12-13 05:12:30 +04:00
static SIMPLE_DEV_PM_OPS ( s5m_rtc_pm_ops , s5m_rtc_suspend , s5m_rtc_resume ) ;
2013-11-13 03:11:04 +04:00
static const struct platform_device_id s5m_rtc_id [ ] = {
2014-06-11 02:18:46 +04:00
{ " s5m-rtc " , S5M8767X } ,
2015-04-16 22:45:45 +03:00
{ " s2mps13-rtc " , S2MPS13X } ,
2014-06-11 02:18:46 +04:00
{ " s2mps14-rtc " , S2MPS14X } ,
2015-11-20 13:37:53 +03:00
{ " s2mps15-rtc " , S2MPS15X } ,
2015-01-26 23:58:46 +03:00
{ } ,
2013-11-13 03:11:04 +04:00
} ;
2015-08-27 13:34:32 +03:00
MODULE_DEVICE_TABLE ( platform , s5m_rtc_id ) ;
2013-11-13 03:11:04 +04:00
static struct platform_driver s5m_rtc_driver = {
. driver = {
. name = " s5m-rtc " ,
2013-12-13 05:12:30 +04:00
. pm = & s5m_rtc_pm_ops ,
2013-11-13 03:11:04 +04:00
} ,
. probe = s5m_rtc_probe ,
. id_table = s5m_rtc_id ,
} ;
module_platform_driver ( s5m_rtc_driver ) ;
/* Module information */
MODULE_AUTHOR ( " Sangbeom Kim <sbkim73@samsung.com> " ) ;
2014-06-11 02:18:46 +04:00
MODULE_DESCRIPTION ( " Samsung S5M/S2MPS14 RTC driver " ) ;
2013-11-13 03:11:04 +04:00
MODULE_LICENSE ( " GPL " ) ;