2008-10-21 01:50:05 +04:00
/*
2009-12-13 23:30:48 +03:00
* rtc - twl . c - - TWL Real Time Clock interface
2008-10-21 01:50:05 +04:00
*
* Copyright ( C ) 2007 MontaVista Software , Inc
* Author : Alexandre Rusev < source @ mvista . com >
*
* Based on original TI driver twl4030 - rtc . c
* Copyright ( C ) 2006 Texas Instruments , Inc .
*
* Based on rtc - omap . c
* Copyright ( C ) 2003 MontaVista Software , Inc .
* Author : George G . Davis < gdavis @ mvista . com > or < source @ mvista . com >
* Copyright ( C ) 2006 David Brownell
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
2015-04-16 22:46:14 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-10-21 01:50:05 +04:00
# include <linux/kernel.h>
2009-01-07 01:42:11 +03:00
# include <linux/errno.h>
2008-10-21 01:50:05 +04:00
# include <linux/init.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/rtc.h>
# include <linux/bcd.h>
# include <linux/platform_device.h>
# include <linux/interrupt.h>
2013-02-22 04:44:28 +04:00
# include <linux/of.h>
2008-10-21 01:50:05 +04:00
2009-12-13 22:05:51 +03:00
# include <linux/i2c/twl.h>
2008-10-21 01:50:05 +04:00
2016-11-23 11:55:56 +03:00
enum twl_class {
TWL_4030 = 0 ,
TWL_6030 ,
} ;
2008-10-21 01:50:05 +04:00
/*
* RTC block register offsets ( use TWL_MODULE_RTC )
*/
2009-12-14 00:16:31 +03:00
enum {
REG_SECONDS_REG = 0 ,
REG_MINUTES_REG ,
REG_HOURS_REG ,
REG_DAYS_REG ,
REG_MONTHS_REG ,
REG_YEARS_REG ,
REG_WEEKS_REG ,
REG_ALARM_SECONDS_REG ,
REG_ALARM_MINUTES_REG ,
REG_ALARM_HOURS_REG ,
REG_ALARM_DAYS_REG ,
REG_ALARM_MONTHS_REG ,
REG_ALARM_YEARS_REG ,
REG_RTC_CTRL_REG ,
REG_RTC_STATUS_REG ,
REG_RTC_INTERRUPTS_REG ,
REG_RTC_COMP_LSB_REG ,
REG_RTC_COMP_MSB_REG ,
} ;
2010-03-06 00:44:23 +03:00
static const u8 twl4030_rtc_reg_map [ ] = {
2009-12-14 00:16:31 +03:00
[ REG_SECONDS_REG ] = 0x00 ,
[ REG_MINUTES_REG ] = 0x01 ,
[ REG_HOURS_REG ] = 0x02 ,
[ REG_DAYS_REG ] = 0x03 ,
[ REG_MONTHS_REG ] = 0x04 ,
[ REG_YEARS_REG ] = 0x05 ,
[ REG_WEEKS_REG ] = 0x06 ,
[ REG_ALARM_SECONDS_REG ] = 0x07 ,
[ REG_ALARM_MINUTES_REG ] = 0x08 ,
[ REG_ALARM_HOURS_REG ] = 0x09 ,
[ REG_ALARM_DAYS_REG ] = 0x0A ,
[ REG_ALARM_MONTHS_REG ] = 0x0B ,
[ REG_ALARM_YEARS_REG ] = 0x0C ,
[ REG_RTC_CTRL_REG ] = 0x0D ,
[ REG_RTC_STATUS_REG ] = 0x0E ,
[ REG_RTC_INTERRUPTS_REG ] = 0x0F ,
[ REG_RTC_COMP_LSB_REG ] = 0x10 ,
[ REG_RTC_COMP_MSB_REG ] = 0x11 ,
} ;
2010-03-06 00:44:23 +03:00
static const u8 twl6030_rtc_reg_map [ ] = {
2009-12-14 00:16:31 +03:00
[ REG_SECONDS_REG ] = 0x00 ,
[ REG_MINUTES_REG ] = 0x01 ,
[ REG_HOURS_REG ] = 0x02 ,
[ REG_DAYS_REG ] = 0x03 ,
[ REG_MONTHS_REG ] = 0x04 ,
[ REG_YEARS_REG ] = 0x05 ,
[ REG_WEEKS_REG ] = 0x06 ,
[ REG_ALARM_SECONDS_REG ] = 0x08 ,
[ REG_ALARM_MINUTES_REG ] = 0x09 ,
[ REG_ALARM_HOURS_REG ] = 0x0A ,
[ REG_ALARM_DAYS_REG ] = 0x0B ,
[ REG_ALARM_MONTHS_REG ] = 0x0C ,
[ REG_ALARM_YEARS_REG ] = 0x0D ,
[ REG_RTC_CTRL_REG ] = 0x10 ,
[ REG_RTC_STATUS_REG ] = 0x11 ,
[ REG_RTC_INTERRUPTS_REG ] = 0x12 ,
[ REG_RTC_COMP_LSB_REG ] = 0x13 ,
[ REG_RTC_COMP_MSB_REG ] = 0x14 ,
} ;
2008-10-21 01:50:05 +04:00
/* RTC_CTRL_REG bitfields */
# define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01
# define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02
# define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04
# define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08
# define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10
# define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20
# define BIT_RTC_CTRL_REG_GET_TIME_M 0x40
2012-04-12 23:49:15 +04:00
# define BIT_RTC_CTRL_REG_RTC_V_OPT 0x80
2008-10-21 01:50:05 +04:00
/* RTC_STATUS_REG bitfields */
# define BIT_RTC_STATUS_REG_RUN_M 0x02
# define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04
# define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08
# define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10
# define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20
# define BIT_RTC_STATUS_REG_ALARM_M 0x40
# define BIT_RTC_STATUS_REG_POWER_UP_M 0x80
/* RTC_INTERRUPTS_REG bitfields */
# define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03
# define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04
# define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08
/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
# define ALL_TIME_REGS 6
/*----------------------------------------------------------------------*/
2016-11-23 11:55:56 +03:00
struct twl_rtc {
struct device * dev ;
struct rtc_device * rtc ;
u8 * reg_map ;
/*
* Cache the value for timer / alarm interrupts register ; this is
* only changed by callers holding rtc ops lock ( or resume ) .
*/
unsigned char rtc_irq_bits ;
bool wake_enabled ;
# ifdef CONFIG_PM_SLEEP
unsigned char irqstat ;
# endif
enum twl_class class ;
} ;
2008-10-21 01:50:05 +04:00
/*
2009-12-13 23:30:48 +03:00
* Supports 1 byte read from TWL RTC register .
2008-10-21 01:50:05 +04:00
*/
2016-11-23 11:55:56 +03:00
static int twl_rtc_read_u8 ( struct twl_rtc * twl_rtc , u8 * data , u8 reg )
2008-10-21 01:50:05 +04:00
{
int ret ;
2016-11-23 11:55:56 +03:00
ret = twl_i2c_read_u8 ( TWL_MODULE_RTC , data , ( twl_rtc - > reg_map [ reg ] ) ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
2015-04-16 22:46:14 +03:00
pr_err ( " Could not read TWL register %X - error %d \n " , reg , ret ) ;
2008-10-21 01:50:05 +04:00
return ret ;
}
/*
2009-12-13 23:30:48 +03:00
* Supports 1 byte write to TWL RTC registers .
2008-10-21 01:50:05 +04:00
*/
2016-11-23 11:55:56 +03:00
static int twl_rtc_write_u8 ( struct twl_rtc * twl_rtc , u8 data , u8 reg )
2008-10-21 01:50:05 +04:00
{
int ret ;
2016-11-23 11:55:56 +03:00
ret = twl_i2c_write_u8 ( TWL_MODULE_RTC , data , ( twl_rtc - > reg_map [ reg ] ) ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
2015-04-16 22:46:14 +03:00
pr_err ( " Could not write TWL register %X - error %d \n " ,
reg , ret ) ;
2008-10-21 01:50:05 +04:00
return ret ;
}
/*
2009-01-16 00:50:52 +03:00
* Enable 1 / second update and / or alarm interrupts .
2008-10-21 01:50:05 +04:00
*/
2016-11-23 11:55:56 +03:00
static int set_rtc_irq_bit ( struct twl_rtc * twl_rtc , unsigned char bit )
2008-10-21 01:50:05 +04:00
{
unsigned char val ;
int ret ;
2012-03-24 02:02:32 +04:00
/* if the bit is set, return from here */
2016-11-23 11:55:56 +03:00
if ( twl_rtc - > rtc_irq_bits & bit )
2012-03-24 02:02:32 +04:00
return 0 ;
2016-11-23 11:55:56 +03:00
val = twl_rtc - > rtc_irq_bits | bit ;
2009-01-16 00:50:52 +03:00
val & = ~ BIT_RTC_INTERRUPTS_REG_EVERY_M ;
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , val , REG_RTC_INTERRUPTS_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret = = 0 )
2016-11-23 11:55:56 +03:00
twl_rtc - > rtc_irq_bits = val ;
2008-10-21 01:50:05 +04:00
return ret ;
}
/*
2009-01-16 00:50:52 +03:00
* Disable update and / or alarm interrupts .
2008-10-21 01:50:05 +04:00
*/
2016-11-23 11:55:56 +03:00
static int mask_rtc_irq_bit ( struct twl_rtc * twl_rtc , unsigned char bit )
2008-10-21 01:50:05 +04:00
{
unsigned char val ;
int ret ;
2012-03-24 02:02:32 +04:00
/* if the bit is clear, return from here */
2016-11-23 11:55:56 +03:00
if ( ! ( twl_rtc - > rtc_irq_bits & bit ) )
2012-03-24 02:02:32 +04:00
return 0 ;
2016-11-23 11:55:56 +03:00
val = twl_rtc - > rtc_irq_bits & ~ bit ;
ret = twl_rtc_write_u8 ( twl_rtc , val , REG_RTC_INTERRUPTS_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret = = 0 )
2016-11-23 11:55:56 +03:00
twl_rtc - > rtc_irq_bits = val ;
2008-10-21 01:50:05 +04:00
return ret ;
}
2009-12-13 23:30:48 +03:00
static int twl_rtc_alarm_irq_enable ( struct device * dev , unsigned enabled )
2008-10-21 01:50:05 +04:00
{
2013-07-04 02:07:53 +04:00
struct platform_device * pdev = to_platform_device ( dev ) ;
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = dev_get_drvdata ( dev ) ;
2013-07-04 02:07:53 +04:00
int irq = platform_get_irq ( pdev , 0 ) ;
2008-10-21 01:50:05 +04:00
int ret ;
2013-07-04 02:07:53 +04:00
if ( enabled ) {
2016-11-23 11:55:56 +03:00
ret = set_rtc_irq_bit ( twl_rtc ,
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ) ;
if ( device_can_wakeup ( dev ) & & ! twl_rtc - > wake_enabled ) {
2013-07-04 02:07:53 +04:00
enable_irq_wake ( irq ) ;
2016-11-23 11:55:56 +03:00
twl_rtc - > wake_enabled = true ;
2013-07-04 02:07:53 +04:00
}
} else {
2016-11-23 11:55:56 +03:00
ret = mask_rtc_irq_bit ( twl_rtc ,
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ) ;
if ( twl_rtc - > wake_enabled ) {
2013-07-04 02:07:53 +04:00
disable_irq_wake ( irq ) ;
2016-11-23 11:55:56 +03:00
twl_rtc - > wake_enabled = false ;
2013-07-04 02:07:53 +04:00
}
}
2008-10-21 01:50:05 +04:00
return ret ;
}
/*
2009-12-13 23:30:48 +03:00
* Gets current TWL RTC time and date parameters .
2008-10-21 01:50:05 +04:00
*
* The RTC ' s time / alarm representation is not what gmtime ( 3 ) requires
* Linux to use :
*
* - Months are 1. .12 vs Linux 0 - 11
* - Years are 0. .99 vs Linux 1900. . N ( we assume 21 st century )
*/
2009-12-13 23:30:48 +03:00
static int twl_rtc_read_time ( struct device * dev , struct rtc_time * tm )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = dev_get_drvdata ( dev ) ;
2012-11-13 12:28:45 +04:00
unsigned char rtc_data [ ALL_TIME_REGS ] ;
2008-10-21 01:50:05 +04:00
int ret ;
u8 save_control ;
2012-04-12 23:49:15 +04:00
u8 rtc_control ;
2008-10-21 01:50:05 +04:00
2016-11-23 11:55:56 +03:00
ret = twl_rtc_read_u8 ( twl_rtc , & save_control , REG_RTC_CTRL_REG ) ;
2012-04-12 23:49:15 +04:00
if ( ret < 0 ) {
dev_err ( dev , " %s: reading CTRL_REG, error %d \n " , __func__ , ret ) ;
2008-10-21 01:50:05 +04:00
return ret ;
2012-04-12 23:49:15 +04:00
}
/* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */
2016-11-23 11:55:56 +03:00
if ( twl_rtc - > class = = TWL_6030 ) {
2012-04-12 23:49:15 +04:00
if ( save_control & BIT_RTC_CTRL_REG_GET_TIME_M ) {
save_control & = ~ BIT_RTC_CTRL_REG_GET_TIME_M ;
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , save_control ,
REG_RTC_CTRL_REG ) ;
2012-04-12 23:49:15 +04:00
if ( ret < 0 ) {
dev_err ( dev , " %s clr GET_TIME, error %d \n " ,
__func__ , ret ) ;
return ret ;
}
}
}
2008-10-21 01:50:05 +04:00
2012-04-12 23:49:15 +04:00
/* Copy RTC counting registers to static registers or latches */
rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M ;
2008-10-21 01:50:05 +04:00
2012-04-12 23:49:15 +04:00
/* for twl6030/32 enable read access to static shadowed registers */
2016-11-23 11:55:56 +03:00
if ( twl_rtc - > class = = TWL_6030 )
2012-04-12 23:49:15 +04:00
rtc_control | = BIT_RTC_CTRL_REG_RTC_V_OPT ;
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , rtc_control , REG_RTC_CTRL_REG ) ;
2012-04-12 23:49:15 +04:00
if ( ret < 0 ) {
dev_err ( dev , " %s: writing CTRL_REG, error %d \n " , __func__ , ret ) ;
2008-10-21 01:50:05 +04:00
return ret ;
2012-04-12 23:49:15 +04:00
}
2008-10-21 01:50:05 +04:00
2009-12-13 23:30:48 +03:00
ret = twl_i2c_read ( TWL_MODULE_RTC , rtc_data ,
2016-11-23 11:55:56 +03:00
( twl_rtc - > reg_map [ REG_SECONDS_REG ] ) , ALL_TIME_REGS ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 ) {
2012-04-12 23:49:15 +04:00
dev_err ( dev , " %s: reading data, error %d \n " , __func__ , ret ) ;
2008-10-21 01:50:05 +04:00
return ret ;
}
2012-04-12 23:49:15 +04:00
/* for twl6030 restore original state of rtc control register */
2016-11-23 11:55:56 +03:00
if ( twl_rtc - > class = = TWL_6030 ) {
ret = twl_rtc_write_u8 ( twl_rtc , save_control , REG_RTC_CTRL_REG ) ;
2012-04-12 23:49:15 +04:00
if ( ret < 0 ) {
dev_err ( dev , " %s: restore CTRL_REG, error %d \n " ,
__func__ , ret ) ;
return ret ;
}
}
2008-10-21 01:50:05 +04:00
tm - > tm_sec = bcd2bin ( rtc_data [ 0 ] ) ;
tm - > tm_min = bcd2bin ( rtc_data [ 1 ] ) ;
tm - > tm_hour = bcd2bin ( rtc_data [ 2 ] ) ;
tm - > tm_mday = bcd2bin ( rtc_data [ 3 ] ) ;
tm - > tm_mon = bcd2bin ( rtc_data [ 4 ] ) - 1 ;
tm - > tm_year = bcd2bin ( rtc_data [ 5 ] ) + 100 ;
return ret ;
}
2009-12-13 23:30:48 +03:00
static int twl_rtc_set_time ( struct device * dev , struct rtc_time * tm )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = dev_get_drvdata ( dev ) ;
2008-10-21 01:50:05 +04:00
unsigned char save_control ;
2012-11-13 12:28:45 +04:00
unsigned char rtc_data [ ALL_TIME_REGS ] ;
2008-10-21 01:50:05 +04:00
int ret ;
2012-11-13 12:28:45 +04:00
rtc_data [ 0 ] = bin2bcd ( tm - > tm_sec ) ;
rtc_data [ 1 ] = bin2bcd ( tm - > tm_min ) ;
rtc_data [ 2 ] = bin2bcd ( tm - > tm_hour ) ;
rtc_data [ 3 ] = bin2bcd ( tm - > tm_mday ) ;
rtc_data [ 4 ] = bin2bcd ( tm - > tm_mon + 1 ) ;
rtc_data [ 5 ] = bin2bcd ( tm - > tm_year - 100 ) ;
2008-10-21 01:50:05 +04:00
/* Stop RTC while updating the TC registers */
2016-11-23 11:55:56 +03:00
ret = twl_rtc_read_u8 ( twl_rtc , & save_control , REG_RTC_CTRL_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
goto out ;
save_control & = ~ BIT_RTC_CTRL_REG_STOP_RTC_M ;
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , save_control , REG_RTC_CTRL_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
goto out ;
/* update all the time registers in one shot */
2009-12-13 23:30:48 +03:00
ret = twl_i2c_write ( TWL_MODULE_RTC , rtc_data ,
2016-11-23 11:55:56 +03:00
( twl_rtc - > reg_map [ REG_SECONDS_REG ] ) , ALL_TIME_REGS ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 ) {
dev_err ( dev , " rtc_set_time error %d \n " , ret ) ;
goto out ;
}
/* Start back RTC */
save_control | = BIT_RTC_CTRL_REG_STOP_RTC_M ;
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , save_control , REG_RTC_CTRL_REG ) ;
2008-10-21 01:50:05 +04:00
out :
return ret ;
}
/*
2009-12-13 23:30:48 +03:00
* Gets current TWL RTC alarm time .
2008-10-21 01:50:05 +04:00
*/
2009-12-13 23:30:48 +03:00
static int twl_rtc_read_alarm ( struct device * dev , struct rtc_wkalrm * alm )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = dev_get_drvdata ( dev ) ;
2012-11-13 12:28:45 +04:00
unsigned char rtc_data [ ALL_TIME_REGS ] ;
2008-10-21 01:50:05 +04:00
int ret ;
2009-12-13 23:30:48 +03:00
ret = twl_i2c_read ( TWL_MODULE_RTC , rtc_data ,
2016-11-23 11:55:56 +03:00
twl_rtc - > reg_map [ REG_ALARM_SECONDS_REG ] , ALL_TIME_REGS ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 ) {
dev_err ( dev , " rtc_read_alarm error %d \n " , ret ) ;
return ret ;
}
/* some of these fields may be wildcard/"match all" */
alm - > time . tm_sec = bcd2bin ( rtc_data [ 0 ] ) ;
alm - > time . tm_min = bcd2bin ( rtc_data [ 1 ] ) ;
alm - > time . tm_hour = bcd2bin ( rtc_data [ 2 ] ) ;
alm - > time . tm_mday = bcd2bin ( rtc_data [ 3 ] ) ;
alm - > time . tm_mon = bcd2bin ( rtc_data [ 4 ] ) - 1 ;
alm - > time . tm_year = bcd2bin ( rtc_data [ 5 ] ) + 100 ;
/* report cached alarm enable state */
2016-11-23 11:55:56 +03:00
if ( twl_rtc - > rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M )
2008-10-21 01:50:05 +04:00
alm - > enabled = 1 ;
return ret ;
}
2009-12-13 23:30:48 +03:00
static int twl_rtc_set_alarm ( struct device * dev , struct rtc_wkalrm * alm )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = dev_get_drvdata ( dev ) ;
2012-11-13 12:28:45 +04:00
unsigned char alarm_data [ ALL_TIME_REGS ] ;
2008-10-21 01:50:05 +04:00
int ret ;
2009-12-13 23:30:48 +03:00
ret = twl_rtc_alarm_irq_enable ( dev , 0 ) ;
2008-10-21 01:50:05 +04:00
if ( ret )
goto out ;
2012-11-13 12:28:45 +04:00
alarm_data [ 0 ] = bin2bcd ( alm - > time . tm_sec ) ;
alarm_data [ 1 ] = bin2bcd ( alm - > time . tm_min ) ;
alarm_data [ 2 ] = bin2bcd ( alm - > time . tm_hour ) ;
alarm_data [ 3 ] = bin2bcd ( alm - > time . tm_mday ) ;
alarm_data [ 4 ] = bin2bcd ( alm - > time . tm_mon + 1 ) ;
alarm_data [ 5 ] = bin2bcd ( alm - > time . tm_year - 100 ) ;
2008-10-21 01:50:05 +04:00
/* update all the alarm registers in one shot */
2009-12-13 23:30:48 +03:00
ret = twl_i2c_write ( TWL_MODULE_RTC , alarm_data ,
2016-11-23 11:55:56 +03:00
twl_rtc - > reg_map [ REG_ALARM_SECONDS_REG ] , ALL_TIME_REGS ) ;
2008-10-21 01:50:05 +04:00
if ( ret ) {
dev_err ( dev , " rtc_set_alarm error %d \n " , ret ) ;
goto out ;
}
if ( alm - > enabled )
2009-12-13 23:30:48 +03:00
ret = twl_rtc_alarm_irq_enable ( dev , 1 ) ;
2008-10-21 01:50:05 +04:00
out :
return ret ;
}
2016-11-23 11:55:56 +03:00
static irqreturn_t twl_rtc_interrupt ( int irq , void * data )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = data ;
2012-03-24 02:02:34 +04:00
unsigned long events ;
2008-10-21 01:50:05 +04:00
int ret = IRQ_NONE ;
int res ;
u8 rd_reg ;
2016-11-23 11:55:56 +03:00
res = twl_rtc_read_u8 ( twl_rtc , & rd_reg , REG_RTC_STATUS_REG ) ;
2008-10-21 01:50:05 +04:00
if ( res )
goto out ;
/*
* Figure out source of interrupt : ALARM or TIMER in RTC_STATUS_REG .
* only one ( ALARM or RTC ) interrupt source may be enabled
* at time , we also could check our results
* by reading RTS_INTERRUPTS_REGISTER [ IT_TIMER , IT_ALARM ]
*/
if ( rd_reg & BIT_RTC_STATUS_REG_ALARM_M )
2012-03-24 02:02:34 +04:00
events = RTC_IRQF | RTC_AF ;
2008-10-21 01:50:05 +04:00
else
2012-03-24 02:02:34 +04:00
events = RTC_IRQF | RTC_PF ;
2008-10-21 01:50:05 +04:00
2016-11-23 11:55:56 +03:00
res = twl_rtc_write_u8 ( twl_rtc , BIT_RTC_STATUS_REG_ALARM_M ,
REG_RTC_STATUS_REG ) ;
2008-10-21 01:50:05 +04:00
if ( res )
goto out ;
2016-11-23 11:55:56 +03:00
if ( twl_rtc - > class = = TWL_4030 ) {
2009-12-14 00:16:31 +03:00
/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
* needs 2 reads to clear the interrupt . One read is done in
* do_twl_pwrirq ( ) . Doing the second read , to clear
* the bit .
*
* FIXME the reason PWR_ISR1 needs an extra read is that
* RTC_IF retriggered until we cleared REG_ALARM_M above .
* But re - reading like this is a bad hack ; by doing so we
* risk wrongly clearing status for some other IRQ ( losing
* the interrupt ) . Be smarter about handling RTC_UF . . .
*/
res = twl_i2c_read_u8 ( TWL4030_MODULE_INT ,
2008-10-21 01:50:05 +04:00
& rd_reg , TWL4030_INT_PWR_ISR1 ) ;
2009-12-14 00:16:31 +03:00
if ( res )
goto out ;
}
2008-10-21 01:50:05 +04:00
/* Notify RTC core on event */
2016-11-23 11:55:56 +03:00
rtc_update_irq ( twl_rtc - > rtc , 1 , events ) ;
2008-10-21 01:50:05 +04:00
ret = IRQ_HANDLED ;
out :
return ret ;
}
rtc: constify rtc_class_ops structures
Check for rtc_class_ops structures that are only passed to
devm_rtc_device_register, rtc_device_register,
platform_device_register_data, all of which declare the corresponding
parameter as const. Declare rtc_class_ops structures that have these
properties as const.
The semantic patch that makes this change is as follows:
(http://coccinelle.lip6.fr/)
// <smpl>
@r disable optional_qualifier@
identifier i;
position p;
@@
static struct rtc_class_ops i@p = { ... };
@ok@
identifier r.i;
expression e1,e2,e3,e4;
position p;
@@
(
devm_rtc_device_register(e1,e2,&i@p,e3)
|
rtc_device_register(e1,e2,&i@p,e3)
|
platform_device_register_data(e1,e2,e3,&i@p,e4)
)
@bad@
position p != {r.p,ok.p};
identifier r.i;
@@
i@p
@depends on !bad disable optional_qualifier@
identifier r.i;
@@
static
+const
struct rtc_class_ops i = { ... };
// </smpl>
Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Acked-by: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
2016-08-31 11:05:25 +03:00
static const struct rtc_class_ops twl_rtc_ops = {
2009-12-13 23:30:48 +03:00
. read_time = twl_rtc_read_time ,
. set_time = twl_rtc_set_time ,
. read_alarm = twl_rtc_read_alarm ,
. set_alarm = twl_rtc_set_alarm ,
. alarm_irq_enable = twl_rtc_alarm_irq_enable ,
2008-10-21 01:50:05 +04:00
} ;
/*----------------------------------------------------------------------*/
2012-12-22 01:09:38 +04:00
static int twl_rtc_probe ( struct platform_device * pdev )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc ;
2016-11-23 11:55:57 +03:00
struct device_node * np = pdev - > dev . of_node ;
2011-08-11 07:20:36 +04:00
int ret = - EINVAL ;
2008-10-21 01:50:05 +04:00
int irq = platform_get_irq ( pdev , 0 ) ;
u8 rd_reg ;
2016-11-23 11:55:57 +03:00
if ( ! np ) {
dev_err ( & pdev - > dev , " no DT info \n " ) ;
return - EINVAL ;
}
2009-01-07 01:42:11 +03:00
if ( irq < = 0 )
2014-01-24 03:55:06 +04:00
return ret ;
2008-10-21 01:50:05 +04:00
2016-11-23 11:55:56 +03:00
twl_rtc = devm_kzalloc ( & pdev - > dev , sizeof ( * twl_rtc ) , GFP_KERNEL ) ;
if ( ! twl_rtc )
return - ENOMEM ;
if ( twl_class_is_4030 ( ) ) {
twl_rtc - > class = TWL_4030 ;
twl_rtc - > reg_map = ( u8 * ) twl4030_rtc_reg_map ;
} else if ( twl_class_is_6030 ( ) ) {
twl_rtc - > class = TWL_6030 ;
twl_rtc - > reg_map = ( u8 * ) twl6030_rtc_reg_map ;
} else {
dev_err ( & pdev - > dev , " TWL Class not supported. \n " ) ;
return - EINVAL ;
}
2013-07-04 02:07:55 +04:00
2016-11-23 11:55:56 +03:00
ret = twl_rtc_read_u8 ( twl_rtc , & rd_reg , REG_RTC_STATUS_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
2014-01-24 03:55:06 +04:00
return ret ;
2008-10-21 01:50:05 +04:00
if ( rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M )
dev_warn ( & pdev - > dev , " Power up reset detected. \n " ) ;
if ( rd_reg & BIT_RTC_STATUS_REG_ALARM_M )
dev_warn ( & pdev - > dev , " Pending Alarm interrupt detected. \n " ) ;
/* Clear RTC Power up reset and pending alarm interrupts */
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , rd_reg , REG_RTC_STATUS_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
2014-01-24 03:55:06 +04:00
return ret ;
2008-10-21 01:50:05 +04:00
2016-11-23 11:55:56 +03:00
if ( twl_rtc - > class = = TWL_6030 ) {
2009-12-14 00:16:31 +03:00
twl6030_interrupt_unmask ( TWL6030_RTC_INT_MASK ,
REG_INT_MSK_LINE_A ) ;
twl6030_interrupt_unmask ( TWL6030_RTC_INT_MASK ,
REG_INT_MSK_STS_A ) ;
}
2012-03-24 02:02:33 +04:00
dev_info ( & pdev - > dev , " Enabling TWL-RTC \n " ) ;
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , BIT_RTC_CTRL_REG_STOP_RTC_M ,
REG_RTC_CTRL_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
2014-01-24 03:55:06 +04:00
return ret ;
2008-10-21 01:50:05 +04:00
2012-09-18 01:09:17 +04:00
/* ensure interrupts are disabled, bootloaders can be strange */
2016-11-23 11:55:56 +03:00
ret = twl_rtc_write_u8 ( twl_rtc , 0 , REG_RTC_INTERRUPTS_REG ) ;
2012-09-18 01:09:17 +04:00
if ( ret < 0 )
dev_warn ( & pdev - > dev , " unable to disable interrupt \n " ) ;
2008-10-21 01:50:05 +04:00
/* init cached IRQ enable bits */
2016-11-23 11:55:56 +03:00
ret = twl_rtc_read_u8 ( twl_rtc , & twl_rtc - > rtc_irq_bits ,
REG_RTC_INTERRUPTS_REG ) ;
2008-10-21 01:50:05 +04:00
if ( ret < 0 )
2014-01-24 03:55:06 +04:00
return ret ;
2011-08-11 07:20:36 +04:00
2016-11-23 11:55:56 +03:00
platform_set_drvdata ( pdev , twl_rtc ) ;
2013-08-01 00:53:41 +04:00
device_init_wakeup ( & pdev - > dev , 1 ) ;
2016-11-23 11:55:56 +03:00
twl_rtc - > rtc = devm_rtc_device_register ( & pdev - > dev , pdev - > name ,
2014-01-24 03:55:06 +04:00
& twl_rtc_ops , THIS_MODULE ) ;
2016-11-23 11:55:56 +03:00
if ( IS_ERR ( twl_rtc - > rtc ) ) {
2011-08-11 07:20:36 +04:00
dev_err ( & pdev - > dev , " can't register RTC device, err %ld \n " ,
2016-11-23 11:55:56 +03:00
PTR_ERR ( twl_rtc - > rtc ) ) ;
return PTR_ERR ( twl_rtc - > rtc ) ;
2011-08-11 07:20:36 +04:00
}
2014-01-24 03:55:06 +04:00
ret = devm_request_threaded_irq ( & pdev - > dev , irq , NULL ,
twl_rtc_interrupt ,
IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
2016-11-23 11:55:56 +03:00
dev_name ( & twl_rtc - > rtc - > dev ) , twl_rtc ) ;
2011-08-11 07:20:36 +04:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " IRQ is not free. \n " ) ;
2014-01-24 03:55:06 +04:00
return ret ;
2011-08-11 07:20:36 +04:00
}
2008-10-21 01:50:05 +04:00
2011-08-11 07:20:36 +04:00
return 0 ;
2008-10-21 01:50:05 +04:00
}
/*
2009-12-13 23:30:48 +03:00
* Disable all TWL RTC module interrupts .
2008-10-21 01:50:05 +04:00
* Sets status flag to free .
*/
2012-12-22 01:09:38 +04:00
static int twl_rtc_remove ( struct platform_device * pdev )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = platform_get_drvdata ( pdev ) ;
2008-10-21 01:50:05 +04:00
/* leave rtc running, but disable irqs */
2016-11-23 11:55:56 +03:00
mask_rtc_irq_bit ( twl_rtc , BIT_RTC_INTERRUPTS_REG_IT_ALARM_M ) ;
mask_rtc_irq_bit ( twl_rtc , BIT_RTC_INTERRUPTS_REG_IT_TIMER_M ) ;
if ( twl_rtc - > class = = TWL_6030 ) {
2009-12-14 00:16:31 +03:00
twl6030_interrupt_mask ( TWL6030_RTC_INT_MASK ,
REG_INT_MSK_LINE_A ) ;
twl6030_interrupt_mask ( TWL6030_RTC_INT_MASK ,
REG_INT_MSK_STS_A ) ;
}
2008-10-21 01:50:05 +04:00
return 0 ;
}
2009-12-13 23:30:48 +03:00
static void twl_rtc_shutdown ( struct platform_device * pdev )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = platform_get_drvdata ( pdev ) ;
2009-01-16 00:50:56 +03:00
/* mask timer interrupts, but leave alarm interrupts on to enable
power - on when alarm is triggered */
2016-11-23 11:55:56 +03:00
mask_rtc_irq_bit ( twl_rtc , BIT_RTC_INTERRUPTS_REG_IT_TIMER_M ) ;
2008-10-21 01:50:05 +04:00
}
2013-04-30 03:21:04 +04:00
# ifdef CONFIG_PM_SLEEP
static int twl_rtc_suspend ( struct device * dev )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = dev_get_drvdata ( dev ) ;
2008-10-21 01:50:05 +04:00
2016-11-23 11:55:56 +03:00
twl_rtc - > irqstat = twl_rtc - > rtc_irq_bits ;
mask_rtc_irq_bit ( twl_rtc , BIT_RTC_INTERRUPTS_REG_IT_TIMER_M ) ;
2008-10-21 01:50:05 +04:00
return 0 ;
}
2013-04-30 03:21:04 +04:00
static int twl_rtc_resume ( struct device * dev )
2008-10-21 01:50:05 +04:00
{
2016-11-23 11:55:56 +03:00
struct twl_rtc * twl_rtc = dev_get_drvdata ( dev ) ;
set_rtc_irq_bit ( twl_rtc , twl_rtc - > irqstat ) ;
2008-10-21 01:50:05 +04:00
return 0 ;
}
# endif
2013-04-30 03:21:04 +04:00
static SIMPLE_DEV_PM_OPS ( twl_rtc_pm_ops , twl_rtc_suspend , twl_rtc_resume ) ;
2012-01-11 03:10:59 +04:00
static const struct of_device_id twl_rtc_of_match [ ] = {
{ . compatible = " ti,twl4030-rtc " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , twl_rtc_of_match ) ;
2008-10-21 01:50:05 +04:00
static struct platform_driver twl4030rtc_driver = {
2009-12-13 23:30:48 +03:00
. probe = twl_rtc_probe ,
2012-12-22 01:09:38 +04:00
. remove = twl_rtc_remove ,
2009-12-13 23:30:48 +03:00
. shutdown = twl_rtc_shutdown ,
2008-10-21 01:50:05 +04:00
. driver = {
2012-01-11 03:10:59 +04:00
. name = " twl_rtc " ,
2013-04-30 03:21:04 +04:00
. pm = & twl_rtc_pm_ops ,
2016-11-23 11:55:57 +03:00
. of_match_table = twl_rtc_of_match ,
2008-10-21 01:50:05 +04:00
} ,
} ;
2013-07-04 02:07:56 +04:00
module_platform_driver ( twl4030rtc_driver ) ;
2008-10-21 01:50:05 +04:00
MODULE_AUTHOR ( " Texas Instruments, MontaVista Software " ) ;
MODULE_LICENSE ( " GPL " ) ;