2018-08-07 19:19:18 +03:00
// SPDX-License-Identifier: GPL-2.0+
//
// RTC driver for Maxim MAX77686 and MAX77802
//
// Copyright (C) 2012 Samsung Electronics Co.Ltd
//
// based on rtc-max8997.c
2013-02-22 04:44:26 +04:00
2016-02-09 20:26:34 +03:00
# include <linux/i2c.h>
2013-02-22 04:44:26 +04:00
# include <linux/slab.h>
# include <linux/rtc.h>
# include <linux/delay.h>
# include <linux/mutex.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/mfd/max77686-private.h>
# include <linux/irqdomain.h>
# include <linux/regmap.h>
2016-02-09 20:26:34 +03:00
# define MAX77686_I2C_ADDR_RTC (0x0C >> 1)
2016-03-02 11:36:24 +03:00
# define MAX77620_I2C_ADDR_RTC 0x68
2022-02-23 20:59:08 +03:00
# define MAX77714_I2C_ADDR_RTC 0x48
2016-02-09 20:26:34 +03:00
# define MAX77686_INVALID_I2C_ADDR (-1)
2016-03-02 11:36:24 +03:00
/* Define non existing register */
# define MAX77686_INVALID_REG (-1)
2013-02-22 04:44:26 +04:00
/* RTC Control Register */
# define BCD_EN_SHIFT 0
2016-02-09 20:26:30 +03:00
# define BCD_EN_MASK BIT(BCD_EN_SHIFT)
2013-02-22 04:44:26 +04:00
# define MODEL24_SHIFT 1
2016-02-09 20:26:30 +03:00
# define MODEL24_MASK BIT(MODEL24_SHIFT)
2013-02-22 04:44:26 +04:00
/* RTC Update Register1 */
# define RTC_UDR_SHIFT 0
2016-02-09 20:26:30 +03:00
# define RTC_UDR_MASK BIT(RTC_UDR_SHIFT)
2013-02-22 04:44:26 +04:00
# define RTC_RBUDR_SHIFT 4
2016-02-09 20:26:30 +03:00
# define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT)
2013-02-22 04:44:26 +04:00
/* RTC Alarm Enable */
# define ALARM_ENABLE_SHIFT 7
2016-02-09 20:26:30 +03:00
# define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT)
2013-02-22 04:44:26 +04:00
2016-01-27 06:36:42 +03:00
# define REG_RTC_NONE 0xdeadbeef
/*
* MAX77802 has separate register ( RTCAE1 ) for alarm enable instead
* using 1 bit from registers RTC { SEC , MIN , HOUR , DAY , MONTH , YEAR , DATE }
* as in done in MAX77686 .
*/
# define MAX77802_ALARM_ENABLE_VALUE 0x77
2013-02-22 04:44:26 +04:00
enum {
RTC_SEC = 0 ,
RTC_MIN ,
RTC_HOUR ,
RTC_WEEKDAY ,
RTC_MONTH ,
RTC_YEAR ,
2022-02-23 20:59:02 +03:00
RTC_MONTHDAY ,
2013-02-22 04:44:26 +04:00
RTC_NR_TIME
} ;
2022-02-23 20:59:01 +03:00
/**
* struct max77686_rtc_driver_data - model - specific configuration
* @ delay : Minimum usecs needed for a RTC update
* @ mask : Mask used to read RTC registers value
* @ map : Registers offset to I2C addresses map
* @ alarm_enable_reg : Has a separate alarm enable register ?
* @ rtc_i2c_addr : I2C address for RTC block
* @ rtc_irq_from_platform : RTC interrupt via platform resource
* @ alarm_pending_status_reg : Pending alarm status register
* @ rtc_irq_chip : RTC IRQ CHIP for regmap
* @ regmap_config : regmap configuration for the chip
*/
2016-01-27 06:36:40 +03:00
struct max77686_rtc_driver_data {
unsigned long delay ;
u8 mask ;
2016-01-27 06:36:41 +03:00
const unsigned int * map ;
2016-01-27 06:36:42 +03:00
bool alarm_enable_reg ;
2016-02-09 20:26:34 +03:00
int rtc_i2c_addr ;
2016-03-02 11:36:24 +03:00
bool rtc_irq_from_platform ;
int alarm_pending_status_reg ;
2016-02-09 20:26:34 +03:00
const struct regmap_irq_chip * rtc_irq_chip ;
2020-04-17 20:08:25 +03:00
const struct regmap_config * regmap_config ;
2016-01-27 06:36:40 +03:00
} ;
2013-02-22 04:44:26 +04:00
struct max77686_rtc_info {
struct device * dev ;
struct i2c_client * rtc ;
struct rtc_device * rtc_dev ;
struct mutex lock ;
struct regmap * regmap ;
2016-02-09 20:26:32 +03:00
struct regmap * rtc_regmap ;
2013-02-22 04:44:26 +04:00
2016-01-27 06:36:40 +03:00
const struct max77686_rtc_driver_data * drv_data ;
2016-02-09 20:26:34 +03:00
struct regmap_irq_chip_data * rtc_irq_data ;
2016-01-27 06:36:40 +03:00
2016-02-09 20:26:34 +03:00
int rtc_irq ;
2013-02-22 04:44:26 +04:00
int virq ;
} ;
enum MAX77686_RTC_OP {
MAX77686_RTC_WRITE ,
MAX77686_RTC_READ ,
} ;
2016-01-27 06:36:41 +03:00
/* These are not registers but just offsets that are mapped to addresses */
enum max77686_rtc_reg_offset {
REG_RTC_CONTROLM = 0 ,
REG_RTC_CONTROL ,
REG_RTC_UPDATE0 ,
REG_WTSR_SMPL_CNTL ,
REG_RTC_SEC ,
REG_RTC_MIN ,
REG_RTC_HOUR ,
REG_RTC_WEEKDAY ,
REG_RTC_MONTH ,
REG_RTC_YEAR ,
2022-02-23 20:59:02 +03:00
REG_RTC_MONTHDAY ,
2016-01-27 06:36:41 +03:00
REG_ALARM1_SEC ,
REG_ALARM1_MIN ,
REG_ALARM1_HOUR ,
REG_ALARM1_WEEKDAY ,
REG_ALARM1_MONTH ,
REG_ALARM1_YEAR ,
REG_ALARM1_DATE ,
REG_ALARM2_SEC ,
REG_ALARM2_MIN ,
REG_ALARM2_HOUR ,
REG_ALARM2_WEEKDAY ,
REG_ALARM2_MONTH ,
REG_ALARM2_YEAR ,
REG_ALARM2_DATE ,
2016-01-27 06:36:42 +03:00
REG_RTC_AE1 ,
2016-01-27 06:36:41 +03:00
REG_RTC_END ,
} ;
/* Maps RTC registers offset to the MAX77686 register addresses */
static const unsigned int max77686_map [ REG_RTC_END ] = {
[ REG_RTC_CONTROLM ] = MAX77686_RTC_CONTROLM ,
[ REG_RTC_CONTROL ] = MAX77686_RTC_CONTROL ,
[ REG_RTC_UPDATE0 ] = MAX77686_RTC_UPDATE0 ,
[ REG_WTSR_SMPL_CNTL ] = MAX77686_WTSR_SMPL_CNTL ,
[ REG_RTC_SEC ] = MAX77686_RTC_SEC ,
[ REG_RTC_MIN ] = MAX77686_RTC_MIN ,
[ REG_RTC_HOUR ] = MAX77686_RTC_HOUR ,
[ REG_RTC_WEEKDAY ] = MAX77686_RTC_WEEKDAY ,
[ REG_RTC_MONTH ] = MAX77686_RTC_MONTH ,
[ REG_RTC_YEAR ] = MAX77686_RTC_YEAR ,
2022-02-23 20:59:02 +03:00
[ REG_RTC_MONTHDAY ] = MAX77686_RTC_MONTHDAY ,
2016-01-27 06:36:41 +03:00
[ REG_ALARM1_SEC ] = MAX77686_ALARM1_SEC ,
[ REG_ALARM1_MIN ] = MAX77686_ALARM1_MIN ,
[ REG_ALARM1_HOUR ] = MAX77686_ALARM1_HOUR ,
[ REG_ALARM1_WEEKDAY ] = MAX77686_ALARM1_WEEKDAY ,
[ REG_ALARM1_MONTH ] = MAX77686_ALARM1_MONTH ,
[ REG_ALARM1_YEAR ] = MAX77686_ALARM1_YEAR ,
[ REG_ALARM1_DATE ] = MAX77686_ALARM1_DATE ,
[ REG_ALARM2_SEC ] = MAX77686_ALARM2_SEC ,
[ REG_ALARM2_MIN ] = MAX77686_ALARM2_MIN ,
[ REG_ALARM2_HOUR ] = MAX77686_ALARM2_HOUR ,
[ REG_ALARM2_WEEKDAY ] = MAX77686_ALARM2_WEEKDAY ,
[ REG_ALARM2_MONTH ] = MAX77686_ALARM2_MONTH ,
[ REG_ALARM2_YEAR ] = MAX77686_ALARM2_YEAR ,
[ REG_ALARM2_DATE ] = MAX77686_ALARM2_DATE ,
2016-01-27 06:36:42 +03:00
[ REG_RTC_AE1 ] = REG_RTC_NONE ,
2016-01-27 06:36:41 +03:00
} ;
2016-02-09 20:26:34 +03:00
static const struct regmap_irq max77686_rtc_irqs [ ] = {
/* RTC interrupts */
2016-03-02 11:36:25 +03:00
REGMAP_IRQ_REG ( 0 , 0 , MAX77686_RTCINT_RTC60S_MSK ) ,
REGMAP_IRQ_REG ( 1 , 0 , MAX77686_RTCINT_RTCA1_MSK ) ,
REGMAP_IRQ_REG ( 2 , 0 , MAX77686_RTCINT_RTCA2_MSK ) ,
REGMAP_IRQ_REG ( 3 , 0 , MAX77686_RTCINT_SMPL_MSK ) ,
REGMAP_IRQ_REG ( 4 , 0 , MAX77686_RTCINT_RTC1S_MSK ) ,
REGMAP_IRQ_REG ( 5 , 0 , MAX77686_RTCINT_WTSR_MSK ) ,
2016-02-09 20:26:34 +03:00
} ;
static const struct regmap_irq_chip max77686_rtc_irq_chip = {
. name = " max77686-rtc " ,
. status_base = MAX77686_RTC_INT ,
. mask_base = MAX77686_RTC_INTM ,
. num_regs = 1 ,
. irqs = max77686_rtc_irqs ,
. num_irqs = ARRAY_SIZE ( max77686_rtc_irqs ) ,
} ;
2020-04-17 20:08:25 +03:00
static const struct regmap_config max77686_rtc_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
2016-01-27 06:36:40 +03:00
static const struct max77686_rtc_driver_data max77686_drv_data = {
. delay = 16000 ,
. mask = 0x7f ,
2016-01-27 06:36:41 +03:00
. map = max77686_map ,
2016-01-27 06:36:42 +03:00
. alarm_enable_reg = false ,
2016-03-02 11:36:24 +03:00
. rtc_irq_from_platform = false ,
. alarm_pending_status_reg = MAX77686_REG_STATUS2 ,
2016-02-09 20:26:34 +03:00
. rtc_i2c_addr = MAX77686_I2C_ADDR_RTC ,
. rtc_irq_chip = & max77686_rtc_irq_chip ,
2020-04-17 20:08:25 +03:00
. regmap_config = & max77686_rtc_regmap_config ,
} ;
2022-02-23 20:59:08 +03:00
static const struct regmap_irq_chip max77714_rtc_irq_chip = {
. name = " max77714-rtc " ,
. status_base = MAX77686_RTC_INT ,
. mask_base = MAX77686_RTC_INTM ,
. num_regs = 1 ,
. irqs = max77686_rtc_irqs ,
. num_irqs = ARRAY_SIZE ( max77686_rtc_irqs ) - 1 , /* no WTSR on 77714 */
} ;
static const struct max77686_rtc_driver_data max77714_drv_data = {
. delay = 16000 ,
. mask = 0x7f ,
. map = max77686_map ,
. alarm_enable_reg = false ,
. rtc_irq_from_platform = false ,
/* On MAX77714 RTCA1 is BIT 1 of RTCINT (0x00). Not supported by this driver. */
. alarm_pending_status_reg = MAX77686_INVALID_REG ,
. rtc_i2c_addr = MAX77714_I2C_ADDR_RTC ,
. rtc_irq_chip = & max77714_rtc_irq_chip ,
. regmap_config = & max77686_rtc_regmap_config ,
} ;
2020-04-17 20:08:25 +03:00
static const struct regmap_config max77620_rtc_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. use_single_write = true ,
2016-01-27 06:36:42 +03:00
} ;
2016-03-02 11:36:24 +03:00
static const struct max77686_rtc_driver_data max77620_drv_data = {
. delay = 16000 ,
. mask = 0x7f ,
. map = max77686_map ,
. alarm_enable_reg = false ,
. rtc_irq_from_platform = true ,
. alarm_pending_status_reg = MAX77686_INVALID_REG ,
. rtc_i2c_addr = MAX77620_I2C_ADDR_RTC ,
. rtc_irq_chip = & max77686_rtc_irq_chip ,
2020-04-17 20:08:25 +03:00
. regmap_config = & max77620_rtc_regmap_config ,
2016-03-02 11:36:24 +03:00
} ;
2016-01-27 06:36:42 +03:00
static const unsigned int max77802_map [ REG_RTC_END ] = {
[ REG_RTC_CONTROLM ] = MAX77802_RTC_CONTROLM ,
[ REG_RTC_CONTROL ] = MAX77802_RTC_CONTROL ,
[ REG_RTC_UPDATE0 ] = MAX77802_RTC_UPDATE0 ,
[ REG_WTSR_SMPL_CNTL ] = MAX77802_WTSR_SMPL_CNTL ,
[ REG_RTC_SEC ] = MAX77802_RTC_SEC ,
[ REG_RTC_MIN ] = MAX77802_RTC_MIN ,
[ REG_RTC_HOUR ] = MAX77802_RTC_HOUR ,
[ REG_RTC_WEEKDAY ] = MAX77802_RTC_WEEKDAY ,
[ REG_RTC_MONTH ] = MAX77802_RTC_MONTH ,
[ REG_RTC_YEAR ] = MAX77802_RTC_YEAR ,
2022-02-23 20:59:02 +03:00
[ REG_RTC_MONTHDAY ] = MAX77802_RTC_MONTHDAY ,
2016-01-27 06:36:42 +03:00
[ REG_ALARM1_SEC ] = MAX77802_ALARM1_SEC ,
[ REG_ALARM1_MIN ] = MAX77802_ALARM1_MIN ,
[ REG_ALARM1_HOUR ] = MAX77802_ALARM1_HOUR ,
[ REG_ALARM1_WEEKDAY ] = MAX77802_ALARM1_WEEKDAY ,
[ REG_ALARM1_MONTH ] = MAX77802_ALARM1_MONTH ,
[ REG_ALARM1_YEAR ] = MAX77802_ALARM1_YEAR ,
[ REG_ALARM1_DATE ] = MAX77802_ALARM1_DATE ,
[ REG_ALARM2_SEC ] = MAX77802_ALARM2_SEC ,
[ REG_ALARM2_MIN ] = MAX77802_ALARM2_MIN ,
[ REG_ALARM2_HOUR ] = MAX77802_ALARM2_HOUR ,
[ REG_ALARM2_WEEKDAY ] = MAX77802_ALARM2_WEEKDAY ,
[ REG_ALARM2_MONTH ] = MAX77802_ALARM2_MONTH ,
[ REG_ALARM2_YEAR ] = MAX77802_ALARM2_YEAR ,
[ REG_ALARM2_DATE ] = MAX77802_ALARM2_DATE ,
[ REG_RTC_AE1 ] = MAX77802_RTC_AE1 ,
} ;
2016-02-09 20:26:34 +03:00
static const struct regmap_irq_chip max77802_rtc_irq_chip = {
. name = " max77802-rtc " ,
. status_base = MAX77802_RTC_INT ,
. mask_base = MAX77802_RTC_INTM ,
. num_regs = 1 ,
. irqs = max77686_rtc_irqs , /* same masks as 77686 */
. num_irqs = ARRAY_SIZE ( max77686_rtc_irqs ) ,
} ;
2016-01-27 06:36:42 +03:00
static const struct max77686_rtc_driver_data max77802_drv_data = {
. delay = 200 ,
. mask = 0xff ,
. map = max77802_map ,
. alarm_enable_reg = true ,
2016-03-02 11:36:24 +03:00
. rtc_irq_from_platform = false ,
. alarm_pending_status_reg = MAX77686_REG_STATUS2 ,
2016-02-09 20:26:34 +03:00
. rtc_i2c_addr = MAX77686_INVALID_I2C_ADDR ,
. rtc_irq_chip = & max77802_rtc_irq_chip ,
2016-01-27 06:36:40 +03:00
} ;
2013-02-22 04:44:26 +04:00
static void max77686_rtc_data_to_tm ( u8 * data , struct rtc_time * tm ,
2016-01-27 06:36:40 +03:00
struct max77686_rtc_info * info )
2013-02-22 04:44:26 +04:00
{
2016-01-27 06:36:40 +03:00
u8 mask = info - > drv_data - > mask ;
tm - > tm_sec = data [ RTC_SEC ] & mask ;
tm - > tm_min = data [ RTC_MIN ] & mask ;
2022-02-23 20:59:03 +03:00
tm - > tm_hour = data [ RTC_HOUR ] & 0x1f ;
2013-02-22 04:44:26 +04:00
2014-10-14 02:53:03 +04:00
/* Only a single bit is set in data[], so fls() would be equivalent */
2016-01-27 06:36:40 +03:00
tm - > tm_wday = ffs ( data [ RTC_WEEKDAY ] & mask ) - 1 ;
2022-02-23 20:59:02 +03:00
tm - > tm_mday = data [ RTC_MONTHDAY ] & 0x1f ;
2013-02-22 04:44:26 +04:00
tm - > tm_mon = ( data [ RTC_MONTH ] & 0x0f ) - 1 ;
2016-01-27 06:36:42 +03:00
tm - > tm_year = data [ RTC_YEAR ] & mask ;
2013-02-22 04:44:26 +04:00
tm - > tm_yday = 0 ;
tm - > tm_isdst = 0 ;
2016-01-27 06:36:42 +03:00
/*
* MAX77686 uses 1 bit from sec / min / hour / etc RTC registers and the
* year values are just 0. .99 so add 100 to support up to 2099.
*/
if ( ! info - > drv_data - > alarm_enable_reg )
tm - > tm_year + = 100 ;
2013-02-22 04:44:26 +04:00
}
2016-01-27 06:36:42 +03:00
static int max77686_rtc_tm_to_data ( struct rtc_time * tm , u8 * data ,
struct max77686_rtc_info * info )
2013-02-22 04:44:26 +04:00
{
data [ RTC_SEC ] = tm - > tm_sec ;
data [ RTC_MIN ] = tm - > tm_min ;
data [ RTC_HOUR ] = tm - > tm_hour ;
data [ RTC_WEEKDAY ] = 1 < < tm - > tm_wday ;
2022-02-23 20:59:02 +03:00
data [ RTC_MONTHDAY ] = tm - > tm_mday ;
2013-02-22 04:44:26 +04:00
data [ RTC_MONTH ] = tm - > tm_mon + 1 ;
2016-01-27 06:36:42 +03:00
if ( info - > drv_data - > alarm_enable_reg ) {
data [ RTC_YEAR ] = tm - > tm_year ;
return 0 ;
}
2013-07-04 02:05:55 +04:00
data [ RTC_YEAR ] = tm - > tm_year > 100 ? ( tm - > tm_year - 100 ) : 0 ;
2013-02-22 04:44:26 +04:00
if ( tm - > tm_year < 100 ) {
2016-01-27 06:36:43 +03:00
dev_err ( info - > dev , " RTC cannot handle the year %d. \n " ,
2015-04-16 22:46:14 +03:00
1900 + tm - > tm_year ) ;
2013-02-22 04:44:26 +04:00
return - EINVAL ;
}
2016-01-27 06:36:42 +03:00
2013-02-22 04:44:26 +04:00
return 0 ;
}
static int max77686_rtc_update ( struct max77686_rtc_info * info ,
2016-02-09 20:26:30 +03:00
enum MAX77686_RTC_OP op )
2013-02-22 04:44:26 +04:00
{
int ret ;
unsigned int data ;
2016-01-27 06:36:40 +03:00
unsigned long delay = info - > drv_data - > delay ;
2013-02-22 04:44:26 +04:00
if ( op = = MAX77686_RTC_WRITE )
data = 1 < < RTC_UDR_SHIFT ;
else
data = 1 < < RTC_RBUDR_SHIFT ;
2016-02-09 20:26:32 +03:00
ret = regmap_update_bits ( info - > rtc_regmap ,
2016-01-27 06:36:41 +03:00
info - > drv_data - > map [ REG_RTC_UPDATE0 ] ,
data , data ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 )
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to write update reg(ret=%d, data=0x%x) \n " ,
ret , data ) ;
2013-02-22 04:44:26 +04:00
else {
2016-01-27 06:36:40 +03:00
/* Minimum delay required before RTC update. */
usleep_range ( delay , delay * 2 ) ;
2013-02-22 04:44:26 +04:00
}
return ret ;
}
static int max77686_rtc_read_time ( struct device * dev , struct rtc_time * tm )
{
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
u8 data [ RTC_NR_TIME ] ;
int ret ;
mutex_lock ( & info - > lock ) ;
ret = max77686_rtc_update ( info , MAX77686_RTC_READ ) ;
if ( ret < 0 )
goto out ;
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_read ( info - > rtc_regmap ,
2016-01-27 06:36:41 +03:00
info - > drv_data - > map [ REG_RTC_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to read time reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
goto out ;
}
2016-01-27 06:36:40 +03:00
max77686_rtc_data_to_tm ( data , tm , info ) ;
2013-02-22 04:44:26 +04:00
out :
mutex_unlock ( & info - > lock ) ;
2018-11-14 02:36:45 +03:00
return ret ;
2013-02-22 04:44:26 +04:00
}
static int max77686_rtc_set_time ( struct device * dev , struct rtc_time * tm )
{
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
u8 data [ RTC_NR_TIME ] ;
int ret ;
2016-01-27 06:36:42 +03:00
ret = max77686_rtc_tm_to_data ( tm , data , info ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 )
return ret ;
mutex_lock ( & info - > lock ) ;
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_write ( info - > rtc_regmap ,
2016-01-27 06:36:41 +03:00
info - > drv_data - > map [ REG_RTC_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to write time reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
goto out ;
}
ret = max77686_rtc_update ( info , MAX77686_RTC_WRITE ) ;
out :
mutex_unlock ( & info - > lock ) ;
return ret ;
}
static int max77686_rtc_read_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
u8 data [ RTC_NR_TIME ] ;
unsigned int val ;
2016-01-27 06:36:41 +03:00
const unsigned int * map = info - > drv_data - > map ;
2013-02-22 04:44:26 +04:00
int i , ret ;
mutex_lock ( & info - > lock ) ;
ret = max77686_rtc_update ( info , MAX77686_RTC_READ ) ;
if ( ret < 0 )
goto out ;
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_read ( info - > rtc_regmap , map [ REG_ALARM1_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to read alarm reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
goto out ;
}
2016-01-27 06:36:40 +03:00
max77686_rtc_data_to_tm ( data , & alrm - > time , info ) ;
2013-02-22 04:44:26 +04:00
alrm - > enabled = 0 ;
2016-01-27 06:36:42 +03:00
if ( info - > drv_data - > alarm_enable_reg ) {
if ( map [ REG_RTC_AE1 ] = = REG_RTC_NONE ) {
ret = - EINVAL ;
dev_err ( info - > dev ,
" alarm enable register not set(%d) \n " , ret ) ;
goto out ;
}
2016-02-09 20:26:32 +03:00
ret = regmap_read ( info - > rtc_regmap , map [ REG_RTC_AE1 ] , & val ) ;
2016-01-27 06:36:42 +03:00
if ( ret < 0 ) {
dev_err ( info - > dev ,
" fail to read alarm enable(%d) \n " , ret ) ;
goto out ;
}
if ( val )
2013-02-22 04:44:26 +04:00
alrm - > enabled = 1 ;
2016-01-27 06:36:42 +03:00
} else {
for ( i = 0 ; i < ARRAY_SIZE ( data ) ; i + + ) {
if ( data [ i ] & ALARM_ENABLE_MASK ) {
alrm - > enabled = 1 ;
break ;
}
2013-02-22 04:44:26 +04:00
}
}
alrm - > pending = 0 ;
2016-03-02 11:36:24 +03:00
if ( info - > drv_data - > alarm_pending_status_reg = = MAX77686_INVALID_REG )
goto out ;
ret = regmap_read ( info - > regmap ,
info - > drv_data - > alarm_pending_status_reg , & val ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-03-02 11:36:24 +03:00
dev_err ( info - > dev ,
" Fail to read alarm pending status reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
goto out ;
}
if ( val & ( 1 < < 4 ) ) /* RTCA1 */
alrm - > pending = 1 ;
out :
mutex_unlock ( & info - > lock ) ;
2016-01-27 06:36:37 +03:00
return ret ;
2013-02-22 04:44:26 +04:00
}
static int max77686_rtc_stop_alarm ( struct max77686_rtc_info * info )
{
u8 data [ RTC_NR_TIME ] ;
int ret , i ;
struct rtc_time tm ;
2016-01-27 06:36:41 +03:00
const unsigned int * map = info - > drv_data - > map ;
2013-02-22 04:44:26 +04:00
if ( ! mutex_is_locked ( & info - > lock ) )
dev_warn ( info - > dev , " %s: should have mutex locked \n " , __func__ ) ;
ret = max77686_rtc_update ( info , MAX77686_RTC_READ ) ;
if ( ret < 0 )
goto out ;
2016-01-27 06:36:42 +03:00
if ( info - > drv_data - > alarm_enable_reg ) {
if ( map [ REG_RTC_AE1 ] = = REG_RTC_NONE ) {
ret = - EINVAL ;
dev_err ( info - > dev ,
" alarm enable register not set(%d) \n " , ret ) ;
goto out ;
}
2016-02-09 20:26:32 +03:00
ret = regmap_write ( info - > rtc_regmap , map [ REG_RTC_AE1 ] , 0 ) ;
2016-01-27 06:36:42 +03:00
} else {
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_read ( info - > rtc_regmap , map [ REG_ALARM1_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2016-01-27 06:36:42 +03:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to read alarm reg(%d) \n " , ret ) ;
2016-01-27 06:36:42 +03:00
goto out ;
}
2013-02-22 04:44:26 +04:00
2016-01-27 06:36:42 +03:00
max77686_rtc_data_to_tm ( data , & tm , info ) ;
2013-02-22 04:44:26 +04:00
2016-01-27 06:36:42 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( data ) ; i + + )
data [ i ] & = ~ ALARM_ENABLE_MASK ;
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_write ( info - > rtc_regmap , map [ REG_ALARM1_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2016-01-27 06:36:42 +03:00
}
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to write alarm reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
goto out ;
}
ret = max77686_rtc_update ( info , MAX77686_RTC_WRITE ) ;
out :
return ret ;
}
static int max77686_rtc_start_alarm ( struct max77686_rtc_info * info )
{
u8 data [ RTC_NR_TIME ] ;
int ret ;
struct rtc_time tm ;
2016-01-27 06:36:41 +03:00
const unsigned int * map = info - > drv_data - > map ;
2013-02-22 04:44:26 +04:00
if ( ! mutex_is_locked ( & info - > lock ) )
dev_warn ( info - > dev , " %s: should have mutex locked \n " , __func__ ) ;
ret = max77686_rtc_update ( info , MAX77686_RTC_READ ) ;
if ( ret < 0 )
goto out ;
2016-01-27 06:36:42 +03:00
if ( info - > drv_data - > alarm_enable_reg ) {
2016-02-09 20:26:32 +03:00
ret = regmap_write ( info - > rtc_regmap , map [ REG_RTC_AE1 ] ,
2016-01-27 06:36:42 +03:00
MAX77802_ALARM_ENABLE_VALUE ) ;
} else {
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_read ( info - > rtc_regmap , map [ REG_ALARM1_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2016-01-27 06:36:42 +03:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to read alarm reg(%d) \n " , ret ) ;
2016-01-27 06:36:42 +03:00
goto out ;
}
2013-02-22 04:44:26 +04:00
2016-01-27 06:36:42 +03:00
max77686_rtc_data_to_tm ( data , & tm , info ) ;
data [ RTC_SEC ] | = ( 1 < < ALARM_ENABLE_SHIFT ) ;
data [ RTC_MIN ] | = ( 1 < < ALARM_ENABLE_SHIFT ) ;
data [ RTC_HOUR ] | = ( 1 < < ALARM_ENABLE_SHIFT ) ;
data [ RTC_WEEKDAY ] & = ~ ALARM_ENABLE_MASK ;
if ( data [ RTC_MONTH ] & 0xf )
data [ RTC_MONTH ] | = ( 1 < < ALARM_ENABLE_SHIFT ) ;
if ( data [ RTC_YEAR ] & info - > drv_data - > mask )
data [ RTC_YEAR ] | = ( 1 < < ALARM_ENABLE_SHIFT ) ;
2022-02-23 20:59:02 +03:00
if ( data [ RTC_MONTHDAY ] & 0x1f )
data [ RTC_MONTHDAY ] | = ( 1 < < ALARM_ENABLE_SHIFT ) ;
2016-01-27 06:36:42 +03:00
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_write ( info - > rtc_regmap , map [ REG_ALARM1_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2016-01-27 06:36:42 +03:00
}
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to write alarm reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
goto out ;
}
ret = max77686_rtc_update ( info , MAX77686_RTC_WRITE ) ;
out :
return ret ;
}
static int max77686_rtc_set_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
u8 data [ RTC_NR_TIME ] ;
int ret ;
2016-01-27 06:36:42 +03:00
ret = max77686_rtc_tm_to_data ( & alrm - > time , data , info ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 )
return ret ;
mutex_lock ( & info - > lock ) ;
ret = max77686_rtc_stop_alarm ( info ) ;
if ( ret < 0 )
goto out ;
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_write ( info - > rtc_regmap ,
2016-01-27 06:36:41 +03:00
info - > drv_data - > map [ REG_ALARM1_SEC ] ,
data , ARRAY_SIZE ( data ) ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to write alarm reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
goto out ;
}
ret = max77686_rtc_update ( info , MAX77686_RTC_WRITE ) ;
if ( ret < 0 )
goto out ;
if ( alrm - > enabled )
ret = max77686_rtc_start_alarm ( info ) ;
out :
mutex_unlock ( & info - > lock ) ;
return ret ;
}
static int max77686_rtc_alarm_irq_enable ( struct device * dev ,
2016-02-09 20:26:30 +03:00
unsigned int enabled )
2013-02-22 04:44:26 +04:00
{
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
int ret ;
mutex_lock ( & info - > lock ) ;
if ( enabled )
ret = max77686_rtc_start_alarm ( info ) ;
else
ret = max77686_rtc_stop_alarm ( info ) ;
mutex_unlock ( & info - > lock ) ;
return ret ;
}
static irqreturn_t max77686_rtc_alarm_irq ( int irq , void * data )
{
struct max77686_rtc_info * info = data ;
2016-01-27 09:46:11 +03:00
dev_dbg ( info - > dev , " RTC alarm IRQ: %d \n " , irq ) ;
2013-02-22 04:44:26 +04:00
rtc_update_irq ( info - > rtc_dev , 1 , RTC_IRQF | RTC_AF ) ;
return IRQ_HANDLED ;
}
static const struct rtc_class_ops max77686_rtc_ops = {
. read_time = max77686_rtc_read_time ,
. set_time = max77686_rtc_set_time ,
. read_alarm = max77686_rtc_read_alarm ,
. set_alarm = max77686_rtc_set_alarm ,
. alarm_irq_enable = max77686_rtc_alarm_irq_enable ,
} ;
static int max77686_rtc_init_reg ( struct max77686_rtc_info * info )
{
u8 data [ 2 ] ;
int ret ;
/* Set RTC control register : Binary mode, 24hour mdoe */
data [ 0 ] = ( 1 < < BCD_EN_SHIFT ) | ( 1 < < MODEL24_SHIFT ) ;
data [ 1 ] = ( 0 < < BCD_EN_SHIFT ) | ( 1 < < MODEL24_SHIFT ) ;
2016-02-09 20:26:32 +03:00
ret = regmap_bulk_write ( info - > rtc_regmap ,
2016-01-27 06:36:41 +03:00
info - > drv_data - > map [ REG_RTC_CONTROLM ] ,
data , ARRAY_SIZE ( data ) ) ;
2013-02-22 04:44:26 +04:00
if ( ret < 0 ) {
2016-01-27 09:46:11 +03:00
dev_err ( info - > dev , " Fail to write controlm reg(%d) \n " , ret ) ;
2013-02-22 04:44:26 +04:00
return ret ;
}
ret = max77686_rtc_update ( info , MAX77686_RTC_WRITE ) ;
return ret ;
}
2016-02-09 20:26:34 +03:00
static int max77686_init_rtc_regmap ( struct max77686_rtc_info * info )
{
struct device * parent = info - > dev - > parent ;
struct i2c_client * parent_i2c = to_i2c_client ( parent ) ;
int ret ;
2016-03-02 11:36:24 +03:00
if ( info - > drv_data - > rtc_irq_from_platform ) {
struct platform_device * pdev = to_platform_device ( info - > dev ) ;
info - > rtc_irq = platform_get_irq ( pdev , 0 ) ;
2019-07-30 21:15:39 +03:00
if ( info - > rtc_irq < 0 )
2016-03-02 11:36:24 +03:00
return info - > rtc_irq ;
} else {
info - > rtc_irq = parent_i2c - > irq ;
}
2016-02-09 20:26:34 +03:00
info - > regmap = dev_get_regmap ( parent , NULL ) ;
if ( ! info - > regmap ) {
dev_err ( info - > dev , " Failed to get rtc regmap \n " ) ;
return - ENODEV ;
}
if ( info - > drv_data - > rtc_i2c_addr = = MAX77686_INVALID_I2C_ADDR ) {
info - > rtc_regmap = info - > regmap ;
goto add_rtc_irq ;
}
2019-08-30 16:31:23 +03:00
info - > rtc = devm_i2c_new_dummy_device ( info - > dev , parent_i2c - > adapter ,
info - > drv_data - > rtc_i2c_addr ) ;
2019-07-22 20:26:16 +03:00
if ( IS_ERR ( info - > rtc ) ) {
2016-02-09 20:26:34 +03:00
dev_err ( info - > dev , " Failed to allocate I2C device for RTC \n " ) ;
2019-07-22 20:26:16 +03:00
return PTR_ERR ( info - > rtc ) ;
2016-02-09 20:26:34 +03:00
}
info - > rtc_regmap = devm_regmap_init_i2c ( info - > rtc ,
2020-04-17 20:08:25 +03:00
info - > drv_data - > regmap_config ) ;
2016-02-09 20:26:34 +03:00
if ( IS_ERR ( info - > rtc_regmap ) ) {
ret = PTR_ERR ( info - > rtc_regmap ) ;
dev_err ( info - > dev , " Failed to allocate RTC regmap: %d \n " , ret ) ;
2019-08-30 16:31:23 +03:00
return ret ;
2016-02-09 20:26:34 +03:00
}
add_rtc_irq :
ret = regmap_add_irq_chip ( info - > rtc_regmap , info - > rtc_irq ,
2021-05-26 20:20:34 +03:00
IRQF_ONESHOT | IRQF_SHARED ,
0 , info - > drv_data - > rtc_irq_chip ,
2016-02-09 20:26:34 +03:00
& info - > rtc_irq_data ) ;
if ( ret < 0 ) {
dev_err ( info - > dev , " Failed to add RTC irq chip: %d \n " , ret ) ;
2019-08-30 16:31:23 +03:00
return ret ;
2016-02-09 20:26:34 +03:00
}
return 0 ;
}
2013-02-22 04:44:26 +04:00
static int max77686_rtc_probe ( struct platform_device * pdev )
{
struct max77686_rtc_info * info ;
2016-01-27 06:36:40 +03:00
const struct platform_device_id * id = platform_get_device_id ( pdev ) ;
2014-07-05 00:24:04 +04:00
int ret ;
2013-02-22 04:44:26 +04:00
2013-04-30 03:18:30 +04:00
info = devm_kzalloc ( & pdev - > dev , sizeof ( struct max77686_rtc_info ) ,
2016-02-09 20:26:30 +03:00
GFP_KERNEL ) ;
2013-02-22 04:44:26 +04:00
if ( ! info )
return - ENOMEM ;
mutex_init ( & info - > lock ) ;
info - > dev = & pdev - > dev ;
2016-01-27 06:36:40 +03:00
info - > drv_data = ( const struct max77686_rtc_driver_data * )
id - > driver_data ;
2014-07-05 00:24:04 +04:00
2016-02-09 20:26:34 +03:00
ret = max77686_init_rtc_regmap ( info ) ;
if ( ret < 0 )
return ret ;
2016-01-27 06:36:42 +03:00
2013-02-22 04:44:26 +04:00
platform_set_drvdata ( pdev , info ) ;
ret = max77686_rtc_init_reg ( info ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Failed to initialize RTC reg:%d \n " , ret ) ;
goto err_rtc ;
}
device_init_wakeup ( & pdev - > dev , 1 ) ;
2016-01-27 06:36:42 +03:00
info - > rtc_dev = devm_rtc_device_register ( & pdev - > dev , id - > name ,
2013-04-30 03:19:05 +04:00
& max77686_rtc_ops , THIS_MODULE ) ;
2013-02-22 04:44:26 +04:00
if ( IS_ERR ( info - > rtc_dev ) ) {
ret = PTR_ERR ( info - > rtc_dev ) ;
dev_err ( & pdev - > dev , " Failed to register RTC device: %d \n " , ret ) ;
if ( ret = = 0 )
ret = - EINVAL ;
goto err_rtc ;
}
2014-07-05 00:24:04 +04:00
2016-02-09 20:26:34 +03:00
info - > virq = regmap_irq_get_virq ( info - > rtc_irq_data ,
2014-07-05 00:24:04 +04:00
MAX77686_RTCIRQ_RTCA1 ) ;
2016-02-04 03:26:35 +03:00
if ( info - > virq < = 0 ) {
2013-04-30 03:20:12 +04:00
ret = - ENXIO ;
2013-02-22 04:44:26 +04:00
goto err_rtc ;
2013-04-30 03:20:12 +04:00
}
2013-02-22 04:44:26 +04:00
2016-02-09 20:26:34 +03:00
ret = request_threaded_irq ( info - > virq , NULL , max77686_rtc_alarm_irq , 0 ,
" rtc-alarm1 " , info ) ;
if ( ret < 0 ) {
2013-02-22 04:44:26 +04:00
dev_err ( & pdev - > dev , " Failed to request alarm IRQ: %d: %d \n " ,
info - > virq , ret ) ;
2016-02-09 20:26:34 +03:00
goto err_rtc ;
}
return 0 ;
2013-02-22 04:44:26 +04:00
err_rtc :
2016-02-09 20:26:34 +03:00
regmap_del_irq_chip ( info - > rtc_irq , info - > rtc_irq_data ) ;
2013-02-22 04:44:26 +04:00
return ret ;
}
2023-03-04 16:30:02 +03:00
static void max77686_rtc_remove ( struct platform_device * pdev )
2016-02-09 20:26:34 +03:00
{
struct max77686_rtc_info * info = platform_get_drvdata ( pdev ) ;
free_irq ( info - > virq , info ) ;
regmap_del_irq_chip ( info - > rtc_irq , info - > rtc_irq_data ) ;
}
2014-10-14 02:52:55 +04:00
# ifdef CONFIG_PM_SLEEP
static int max77686_rtc_suspend ( struct device * dev )
{
2020-06-15 19:14:55 +03:00
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
int ret = 0 ;
2014-10-14 02:52:55 +04:00
if ( device_may_wakeup ( dev ) ) {
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
2020-06-15 19:14:55 +03:00
ret = enable_irq_wake ( info - > virq ) ;
2014-10-14 02:52:55 +04:00
}
2020-06-15 19:14:55 +03:00
/*
2020-08-06 15:54:31 +03:00
* If the main IRQ ( not virtual ) is the parent IRQ , then it must be
* disabled during suspend because if it happens while suspended it
* will be handled before resuming I2C .
2020-06-15 19:14:55 +03:00
*
* Since Main IRQ is shared , all its users should disable it to be sure
* it won ' t fire while one of them is still suspended .
*/
2020-08-06 15:54:31 +03:00
if ( ! info - > drv_data - > rtc_irq_from_platform )
disable_irq ( info - > rtc_irq ) ;
2020-06-15 19:14:55 +03:00
return ret ;
2014-10-14 02:52:55 +04:00
}
static int max77686_rtc_resume ( struct device * dev )
{
2020-06-15 19:14:55 +03:00
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
2020-08-06 15:54:31 +03:00
if ( ! info - > drv_data - > rtc_irq_from_platform )
enable_irq ( info - > rtc_irq ) ;
2020-06-15 19:14:55 +03:00
2014-10-14 02:52:55 +04:00
if ( device_may_wakeup ( dev ) ) {
struct max77686_rtc_info * info = dev_get_drvdata ( dev ) ;
return disable_irq_wake ( info - > virq ) ;
}
return 0 ;
}
# endif
static SIMPLE_DEV_PM_OPS ( max77686_rtc_pm_ops ,
max77686_rtc_suspend , max77686_rtc_resume ) ;
2013-02-22 04:44:26 +04:00
static const struct platform_device_id rtc_id [ ] = {
2016-01-27 06:36:40 +03:00
{ " max77686-rtc " , . driver_data = ( kernel_ulong_t ) & max77686_drv_data , } ,
2016-01-27 06:36:42 +03:00
{ " max77802-rtc " , . driver_data = ( kernel_ulong_t ) & max77802_drv_data , } ,
2016-03-02 11:36:24 +03:00
{ " max77620-rtc " , . driver_data = ( kernel_ulong_t ) & max77620_drv_data , } ,
2022-02-23 20:59:08 +03:00
{ " max77714-rtc " , . driver_data = ( kernel_ulong_t ) & max77714_drv_data , } ,
2013-02-22 04:44:26 +04:00
{ } ,
} ;
2015-05-13 18:18:01 +03:00
MODULE_DEVICE_TABLE ( platform , rtc_id ) ;
2013-02-22 04:44:26 +04:00
static struct platform_driver max77686_rtc_driver = {
. driver = {
. name = " max77686-rtc " ,
2014-10-14 02:52:55 +04:00
. pm = & max77686_rtc_pm_ops ,
2013-02-22 04:44:26 +04:00
} ,
. probe = max77686_rtc_probe ,
2023-03-04 16:30:02 +03:00
. remove_new = max77686_rtc_remove ,
2013-02-22 04:44:26 +04:00
. id_table = rtc_id ,
} ;
2013-04-30 03:18:28 +04:00
module_platform_driver ( max77686_rtc_driver ) ;
2013-02-22 04:44:26 +04:00
MODULE_DESCRIPTION ( " Maxim MAX77686 RTC driver " ) ;
2013-04-30 03:18:29 +04:00
MODULE_AUTHOR ( " Chiwoong Byun <woong.byun@samsung.com> " ) ;
2013-02-22 04:44:26 +04:00
MODULE_LICENSE ( " GPL " ) ;