2019-03-18 16:22:55 +03:00
// SPDX-License-Identifier: GPL-2.0+
2006-12-07 07:38:36 +03:00
/*
2014-12-11 02:53:19 +03:00
* TI OMAP Real Time Clock interface for Linux
2006-12-07 07:38:36 +03:00
*
* Copyright ( C ) 2003 MontaVista Software , Inc .
* Author : George G . Davis < gdavis @ mvista . com > or < source @ mvista . com >
*
* Copyright ( C ) 2006 David Brownell ( new RTC framework )
2014-12-11 02:53:22 +03:00
* Copyright ( C ) 2014 Johan Hovold < johan @ kernel . org >
2006-12-07 07:38:36 +03:00
*/
2016-09-16 12:26:28 +03:00
# include <dt-bindings/gpio/gpio.h>
# include <linux/bcd.h>
# include <linux/clk.h>
# include <linux/delay.h>
2006-12-07 07:38:36 +03:00
# include <linux/init.h>
2016-09-16 12:26:28 +03:00
# include <linux/io.h>
2006-12-07 07:38:36 +03:00
# include <linux/ioport.h>
2016-09-16 12:26:28 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
2012-12-18 04:02:15 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
2016-09-16 12:26:28 +03:00
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/platform_device.h>
2012-12-18 04:02:18 +04:00
# include <linux/pm_runtime.h>
2016-09-16 12:26:28 +03:00
# include <linux/rtc.h>
2006-12-07 07:38:36 +03:00
2014-12-11 02:53:19 +03:00
/*
* The OMAP RTC is a year / month / day / hours / minutes / seconds BCD clock
2006-12-07 07:38:36 +03:00
* with century - range alarm matching , driven by the 32 kHz clock .
*
* The main user - visible ways it differs from PC RTCs are by omitting
* " don't care " alarm fields and sub - second periodic IRQs , and having
* an autoadjust mechanism to calibrate to the true oscillator rate .
*
* Board - specific wiring options include using split power mode with
* RTC_OFF_NOFF used as the reset signal ( so the RTC won ' t be reset ) ,
* and wiring RTC_WAKE_INT ( so the RTC alarm can wake the system from
2010-10-28 02:33:05 +04:00
* low power modes ) for OMAP1 boards ( OMAP - L138 has this built into
* the SoC ) . See the BOARD - SPECIFIC CUSTOMIZATION comment .
2006-12-07 07:38:36 +03:00
*/
/* RTC registers */
# define OMAP_RTC_SECONDS_REG 0x00
# define OMAP_RTC_MINUTES_REG 0x04
# define OMAP_RTC_HOURS_REG 0x08
# define OMAP_RTC_DAYS_REG 0x0C
# define OMAP_RTC_MONTHS_REG 0x10
# define OMAP_RTC_YEARS_REG 0x14
# define OMAP_RTC_WEEKS_REG 0x18
# define OMAP_RTC_ALARM_SECONDS_REG 0x20
# define OMAP_RTC_ALARM_MINUTES_REG 0x24
# define OMAP_RTC_ALARM_HOURS_REG 0x28
# define OMAP_RTC_ALARM_DAYS_REG 0x2c
# define OMAP_RTC_ALARM_MONTHS_REG 0x30
# define OMAP_RTC_ALARM_YEARS_REG 0x34
# define OMAP_RTC_CTRL_REG 0x40
# define OMAP_RTC_STATUS_REG 0x44
# define OMAP_RTC_INTERRUPTS_REG 0x48
# define OMAP_RTC_COMP_LSB_REG 0x4c
# define OMAP_RTC_COMP_MSB_REG 0x50
# define OMAP_RTC_OSC_REG 0x54
2017-10-31 19:27:31 +03:00
# define OMAP_RTC_SCRATCH0_REG 0x60
# define OMAP_RTC_SCRATCH1_REG 0x64
# define OMAP_RTC_SCRATCH2_REG 0x68
2012-12-18 04:02:11 +04:00
# define OMAP_RTC_KICK0_REG 0x6c
# define OMAP_RTC_KICK1_REG 0x70
2013-09-12 01:24:18 +04:00
# define OMAP_RTC_IRQWAKEEN 0x7c
2014-12-11 02:53:13 +03:00
# define OMAP_RTC_ALARM2_SECONDS_REG 0x80
# define OMAP_RTC_ALARM2_MINUTES_REG 0x84
# define OMAP_RTC_ALARM2_HOURS_REG 0x88
# define OMAP_RTC_ALARM2_DAYS_REG 0x8c
# define OMAP_RTC_ALARM2_MONTHS_REG 0x90
# define OMAP_RTC_ALARM2_YEARS_REG 0x94
# define OMAP_RTC_PMIC_REG 0x98
2006-12-07 07:38:36 +03:00
/* OMAP_RTC_CTRL_REG bit fields: */
2014-06-07 01:36:05 +04:00
# define OMAP_RTC_CTRL_SPLIT BIT(7)
# define OMAP_RTC_CTRL_DISABLE BIT(6)
# define OMAP_RTC_CTRL_SET_32_COUNTER BIT(5)
# define OMAP_RTC_CTRL_TEST BIT(4)
# define OMAP_RTC_CTRL_MODE_12_24 BIT(3)
# define OMAP_RTC_CTRL_AUTO_COMP BIT(2)
# define OMAP_RTC_CTRL_ROUND_30S BIT(1)
# define OMAP_RTC_CTRL_STOP BIT(0)
2006-12-07 07:38:36 +03:00
/* OMAP_RTC_STATUS_REG bit fields: */
2014-06-07 01:36:05 +04:00
# define OMAP_RTC_STATUS_POWER_UP BIT(7)
2014-12-11 02:53:13 +03:00
# define OMAP_RTC_STATUS_ALARM2 BIT(7)
2014-06-07 01:36:05 +04:00
# define OMAP_RTC_STATUS_ALARM BIT(6)
# define OMAP_RTC_STATUS_1D_EVENT BIT(5)
# define OMAP_RTC_STATUS_1H_EVENT BIT(4)
# define OMAP_RTC_STATUS_1M_EVENT BIT(3)
# define OMAP_RTC_STATUS_1S_EVENT BIT(2)
# define OMAP_RTC_STATUS_RUN BIT(1)
# define OMAP_RTC_STATUS_BUSY BIT(0)
2006-12-07 07:38:36 +03:00
/* OMAP_RTC_INTERRUPTS_REG bit fields: */
2014-12-11 02:53:13 +03:00
# define OMAP_RTC_INTERRUPTS_IT_ALARM2 BIT(4)
2014-06-07 01:36:05 +04:00
# define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3)
# define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2)
2006-12-07 07:38:36 +03:00
2014-06-07 01:36:06 +04:00
/* OMAP_RTC_OSC_REG bit fields: */
# define OMAP_RTC_OSC_32KCLK_EN BIT(6)
2015-08-18 12:41:16 +03:00
# define OMAP_RTC_OSC_SEL_32KCLK_SRC BIT(3)
2016-10-27 08:57:25 +03:00
# define OMAP_RTC_OSC_OSC32K_GZ_DISABLE BIT(4)
2014-06-07 01:36:06 +04:00
2013-09-12 01:24:18 +04:00
/* OMAP_RTC_IRQWAKEEN bit fields: */
2014-06-07 01:36:05 +04:00
# define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1)
2013-09-12 01:24:18 +04:00
2014-12-11 02:53:13 +03:00
/* OMAP_RTC_PMIC bit fields: */
# define OMAP_RTC_PMIC_POWER_EN_EN BIT(16)
2016-09-16 12:26:28 +03:00
# define OMAP_RTC_PMIC_EXT_WKUP_EN(x) BIT(x)
# define OMAP_RTC_PMIC_EXT_WKUP_POL(x) BIT(4 + x)
2014-12-11 02:53:13 +03:00
2012-12-18 04:02:11 +04:00
/* OMAP_RTC_KICKER values */
# define KICK0_VALUE 0x83e70b13
# define KICK1_VALUE 0x95a4f1e0
2015-04-16 22:46:00 +03:00
struct omap_rtc ;
2014-12-11 02:53:01 +03:00
struct omap_rtc_device_type {
bool has_32kclk_en ;
bool has_irqwakeen ;
2014-12-11 02:53:13 +03:00
bool has_pmic_mode ;
2014-12-11 02:53:04 +03:00
bool has_power_up_reset ;
2015-04-16 22:46:00 +03:00
void ( * lock ) ( struct omap_rtc * rtc ) ;
void ( * unlock ) ( struct omap_rtc * rtc ) ;
2014-12-11 02:53:01 +03:00
} ;
2014-06-07 01:36:06 +04:00
2014-12-11 02:52:55 +03:00
struct omap_rtc {
struct rtc_device * rtc ;
void __iomem * base ;
2015-08-18 12:41:15 +03:00
struct clk * clk ;
2014-12-11 02:52:55 +03:00
int irq_alarm ;
int irq_timer ;
u8 interrupts_reg ;
2014-12-11 02:53:13 +03:00
bool is_pmic_controller ;
2015-08-18 12:41:16 +03:00
bool has_ext_clk ;
2016-10-27 08:57:26 +03:00
bool is_suspending ;
2014-12-11 02:53:01 +03:00
const struct omap_rtc_device_type * type ;
2016-09-16 12:26:28 +03:00
struct pinctrl_dev * pctldev ;
2014-12-11 02:52:55 +03:00
} ;
2006-12-07 07:38:36 +03:00
2014-12-11 02:52:55 +03:00
static inline u8 rtc_read ( struct omap_rtc * rtc , unsigned int reg )
{
return readb ( rtc - > base + reg ) ;
}
2012-12-18 04:02:11 +04:00
2014-12-11 02:53:10 +03:00
static inline u32 rtc_readl ( struct omap_rtc * rtc , unsigned int reg )
{
return readl ( rtc - > base + reg ) ;
}
2014-12-11 02:52:55 +03:00
static inline void rtc_write ( struct omap_rtc * rtc , unsigned int reg , u8 val )
{
writeb ( val , rtc - > base + reg ) ;
}
2006-12-07 07:38:36 +03:00
2014-12-11 02:52:55 +03:00
static inline void rtc_writel ( struct omap_rtc * rtc , unsigned int reg , u32 val )
{
writel ( val , rtc - > base + reg ) ;
}
2006-12-07 07:38:36 +03:00
2015-04-16 22:46:00 +03:00
static void am3352_rtc_unlock ( struct omap_rtc * rtc )
{
rtc_writel ( rtc , OMAP_RTC_KICK0_REG , KICK0_VALUE ) ;
rtc_writel ( rtc , OMAP_RTC_KICK1_REG , KICK1_VALUE ) ;
}
static void am3352_rtc_lock ( struct omap_rtc * rtc )
{
rtc_writel ( rtc , OMAP_RTC_KICK0_REG , 0 ) ;
rtc_writel ( rtc , OMAP_RTC_KICK1_REG , 0 ) ;
}
static void default_rtc_unlock ( struct omap_rtc * rtc )
{
}
static void default_rtc_lock ( struct omap_rtc * rtc )
{
}
2014-12-11 02:53:19 +03:00
/*
* We rely on the rtc framework to handle locking ( rtc - > ops_lock ) ,
2006-12-07 07:38:36 +03:00
* so the only other requirement is that register accesses which
* require BUSY to be clear are made with IRQs locally disabled
*/
2014-12-11 02:52:55 +03:00
static void rtc_wait_not_busy ( struct omap_rtc * rtc )
2006-12-07 07:38:36 +03:00
{
2014-12-11 02:53:19 +03:00
int count ;
u8 status ;
2006-12-07 07:38:36 +03:00
/* BUSY may stay active for 1/32768 second (~30 usec) */
for ( count = 0 ; count < 50 ; count + + ) {
2014-12-11 02:52:55 +03:00
status = rtc_read ( rtc , OMAP_RTC_STATUS_REG ) ;
2014-12-11 02:53:19 +03:00
if ( ! ( status & OMAP_RTC_STATUS_BUSY ) )
2006-12-07 07:38:36 +03:00
break ;
udelay ( 1 ) ;
}
/* now we have ~15 usec to read/write various registers */
}
2014-12-11 02:52:55 +03:00
static irqreturn_t rtc_irq ( int irq , void * dev_id )
2006-12-07 07:38:36 +03:00
{
2014-12-11 02:53:19 +03:00
struct omap_rtc * rtc = dev_id ;
unsigned long events = 0 ;
u8 irq_data ;
2006-12-07 07:38:36 +03:00
2014-12-11 02:52:55 +03:00
irq_data = rtc_read ( rtc , OMAP_RTC_STATUS_REG ) ;
2006-12-07 07:38:36 +03:00
/* alarm irq? */
if ( irq_data & OMAP_RTC_STATUS_ALARM ) {
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_STATUS_REG , OMAP_RTC_STATUS_ALARM ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2006-12-07 07:38:36 +03:00
events | = RTC_IRQF | RTC_AF ;
}
/* 1/sec periodic/update irq? */
if ( irq_data & OMAP_RTC_STATUS_1S_EVENT )
events | = RTC_IRQF | RTC_UF ;
2014-12-11 02:52:55 +03:00
rtc_update_irq ( rtc - > rtc , 1 , events ) ;
2006-12-07 07:38:36 +03:00
return IRQ_HANDLED ;
}
2011-02-03 04:02:41 +03:00
static int omap_rtc_alarm_irq_enable ( struct device * dev , unsigned int enabled )
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
2014-06-07 01:36:12 +04:00
u8 reg , irqwake_reg = 0 ;
2011-02-03 04:02:41 +03:00
local_irq_disable ( ) ;
2014-12-11 02:52:55 +03:00
rtc_wait_not_busy ( rtc ) ;
reg = rtc_read ( rtc , OMAP_RTC_INTERRUPTS_REG ) ;
2014-12-11 02:53:01 +03:00
if ( rtc - > type - > has_irqwakeen )
2014-12-11 02:52:55 +03:00
irqwake_reg = rtc_read ( rtc , OMAP_RTC_IRQWAKEEN ) ;
2014-06-07 01:36:12 +04:00
if ( enabled ) {
2011-02-03 04:02:41 +03:00
reg | = OMAP_RTC_INTERRUPTS_IT_ALARM ;
2014-06-07 01:36:12 +04:00
irqwake_reg | = OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN ;
} else {
2011-02-03 04:02:41 +03:00
reg & = ~ OMAP_RTC_INTERRUPTS_IT_ALARM ;
2014-06-07 01:36:12 +04:00
irqwake_reg & = ~ OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN ;
}
2014-12-11 02:52:55 +03:00
rtc_wait_not_busy ( rtc ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_INTERRUPTS_REG , reg ) ;
2014-12-11 02:53:01 +03:00
if ( rtc - > type - > has_irqwakeen )
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_IRQWAKEEN , irqwake_reg ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2011-02-03 04:02:41 +03:00
local_irq_enable ( ) ;
return 0 ;
}
2006-12-07 07:38:36 +03:00
/* this hardware doesn't support "don't care" alarm fields */
2019-03-18 15:44:38 +03:00
static void tm2bcd ( struct rtc_time * tm )
2006-12-07 07:38:36 +03:00
{
2008-10-19 07:28:41 +04:00
tm - > tm_sec = bin2bcd ( tm - > tm_sec ) ;
tm - > tm_min = bin2bcd ( tm - > tm_min ) ;
tm - > tm_hour = bin2bcd ( tm - > tm_hour ) ;
tm - > tm_mday = bin2bcd ( tm - > tm_mday ) ;
2006-12-07 07:38:36 +03:00
2008-10-19 07:28:41 +04:00
tm - > tm_mon = bin2bcd ( tm - > tm_mon + 1 ) ;
tm - > tm_year = bin2bcd ( tm - > tm_year - 100 ) ;
2006-12-07 07:38:36 +03:00
}
static void bcd2tm ( struct rtc_time * tm )
{
2008-10-19 07:28:41 +04:00
tm - > tm_sec = bcd2bin ( tm - > tm_sec ) ;
tm - > tm_min = bcd2bin ( tm - > tm_min ) ;
tm - > tm_hour = bcd2bin ( tm - > tm_hour ) ;
tm - > tm_mday = bcd2bin ( tm - > tm_mday ) ;
tm - > tm_mon = bcd2bin ( tm - > tm_mon ) - 1 ;
2006-12-07 07:38:36 +03:00
/* epoch == 1900 */
2008-10-19 07:28:41 +04:00
tm - > tm_year = bcd2bin ( tm - > tm_year ) + 100 ;
2006-12-07 07:38:36 +03:00
}
2014-12-11 02:53:07 +03:00
static void omap_rtc_read_time_raw ( struct omap_rtc * rtc , struct rtc_time * tm )
2006-12-07 07:38:36 +03:00
{
2014-12-11 02:52:55 +03:00
tm - > tm_sec = rtc_read ( rtc , OMAP_RTC_SECONDS_REG ) ;
tm - > tm_min = rtc_read ( rtc , OMAP_RTC_MINUTES_REG ) ;
tm - > tm_hour = rtc_read ( rtc , OMAP_RTC_HOURS_REG ) ;
tm - > tm_mday = rtc_read ( rtc , OMAP_RTC_DAYS_REG ) ;
tm - > tm_mon = rtc_read ( rtc , OMAP_RTC_MONTHS_REG ) ;
tm - > tm_year = rtc_read ( rtc , OMAP_RTC_YEARS_REG ) ;
2014-12-11 02:53:07 +03:00
}
static int omap_rtc_read_time ( struct device * dev , struct rtc_time * tm )
{
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
2006-12-07 07:38:36 +03:00
2014-12-11 02:53:07 +03:00
/* we don't report wday/yday/isdst ... */
local_irq_disable ( ) ;
rtc_wait_not_busy ( rtc ) ;
omap_rtc_read_time_raw ( rtc , tm ) ;
2006-12-07 07:38:36 +03:00
local_irq_enable ( ) ;
bcd2tm ( tm ) ;
2014-12-11 02:53:19 +03:00
2006-12-07 07:38:36 +03:00
return 0 ;
}
static int omap_rtc_set_time ( struct device * dev , struct rtc_time * tm )
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
2019-03-18 15:44:38 +03:00
tm2bcd ( tm ) ;
2014-12-11 02:53:19 +03:00
2006-12-07 07:38:36 +03:00
local_irq_disable ( ) ;
2014-12-11 02:52:55 +03:00
rtc_wait_not_busy ( rtc ) ;
2006-12-07 07:38:36 +03:00
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_YEARS_REG , tm - > tm_year ) ;
rtc_write ( rtc , OMAP_RTC_MONTHS_REG , tm - > tm_mon ) ;
rtc_write ( rtc , OMAP_RTC_DAYS_REG , tm - > tm_mday ) ;
rtc_write ( rtc , OMAP_RTC_HOURS_REG , tm - > tm_hour ) ;
rtc_write ( rtc , OMAP_RTC_MINUTES_REG , tm - > tm_min ) ;
rtc_write ( rtc , OMAP_RTC_SECONDS_REG , tm - > tm_sec ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2006-12-07 07:38:36 +03:00
local_irq_enable ( ) ;
return 0 ;
}
static int omap_rtc_read_alarm ( struct device * dev , struct rtc_wkalrm * alm )
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
2014-12-11 02:53:19 +03:00
u8 interrupts ;
2014-12-11 02:52:55 +03:00
2006-12-07 07:38:36 +03:00
local_irq_disable ( ) ;
2014-12-11 02:52:55 +03:00
rtc_wait_not_busy ( rtc ) ;
2006-12-07 07:38:36 +03:00
2014-12-11 02:52:55 +03:00
alm - > time . tm_sec = rtc_read ( rtc , OMAP_RTC_ALARM_SECONDS_REG ) ;
alm - > time . tm_min = rtc_read ( rtc , OMAP_RTC_ALARM_MINUTES_REG ) ;
alm - > time . tm_hour = rtc_read ( rtc , OMAP_RTC_ALARM_HOURS_REG ) ;
alm - > time . tm_mday = rtc_read ( rtc , OMAP_RTC_ALARM_DAYS_REG ) ;
alm - > time . tm_mon = rtc_read ( rtc , OMAP_RTC_ALARM_MONTHS_REG ) ;
alm - > time . tm_year = rtc_read ( rtc , OMAP_RTC_ALARM_YEARS_REG ) ;
2006-12-07 07:38:36 +03:00
local_irq_enable ( ) ;
bcd2tm ( & alm - > time ) ;
2014-12-11 02:53:19 +03:00
interrupts = rtc_read ( rtc , OMAP_RTC_INTERRUPTS_REG ) ;
alm - > enabled = ! ! ( interrupts & OMAP_RTC_INTERRUPTS_IT_ALARM ) ;
2006-12-07 07:38:36 +03:00
return 0 ;
}
static int omap_rtc_set_alarm ( struct device * dev , struct rtc_wkalrm * alm )
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
2014-06-07 01:36:12 +04:00
u8 reg , irqwake_reg = 0 ;
2006-12-07 07:38:36 +03:00
2019-03-18 15:44:38 +03:00
tm2bcd ( & alm - > time ) ;
2006-12-07 07:38:36 +03:00
local_irq_disable ( ) ;
2014-12-11 02:52:55 +03:00
rtc_wait_not_busy ( rtc ) ;
2006-12-07 07:38:36 +03:00
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_ALARM_YEARS_REG , alm - > time . tm_year ) ;
rtc_write ( rtc , OMAP_RTC_ALARM_MONTHS_REG , alm - > time . tm_mon ) ;
rtc_write ( rtc , OMAP_RTC_ALARM_DAYS_REG , alm - > time . tm_mday ) ;
rtc_write ( rtc , OMAP_RTC_ALARM_HOURS_REG , alm - > time . tm_hour ) ;
rtc_write ( rtc , OMAP_RTC_ALARM_MINUTES_REG , alm - > time . tm_min ) ;
rtc_write ( rtc , OMAP_RTC_ALARM_SECONDS_REG , alm - > time . tm_sec ) ;
2006-12-07 07:38:36 +03:00
2014-12-11 02:52:55 +03:00
reg = rtc_read ( rtc , OMAP_RTC_INTERRUPTS_REG ) ;
2014-12-11 02:53:01 +03:00
if ( rtc - > type - > has_irqwakeen )
2014-12-11 02:52:55 +03:00
irqwake_reg = rtc_read ( rtc , OMAP_RTC_IRQWAKEEN ) ;
2014-06-07 01:36:12 +04:00
if ( alm - > enabled ) {
2006-12-07 07:38:36 +03:00
reg | = OMAP_RTC_INTERRUPTS_IT_ALARM ;
2014-06-07 01:36:12 +04:00
irqwake_reg | = OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN ;
} else {
2006-12-07 07:38:36 +03:00
reg & = ~ OMAP_RTC_INTERRUPTS_IT_ALARM ;
2014-06-07 01:36:12 +04:00
irqwake_reg & = ~ OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN ;
}
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_INTERRUPTS_REG , reg ) ;
2014-12-11 02:53:01 +03:00
if ( rtc - > type - > has_irqwakeen )
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_IRQWAKEEN , irqwake_reg ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2006-12-07 07:38:36 +03:00
local_irq_enable ( ) ;
return 0 ;
}
2014-12-11 02:53:13 +03:00
static struct omap_rtc * omap_rtc_power_off_rtc ;
2019-04-03 07:57:39 +03:00
/**
* omap_rtc_power_off_program : Set the pmic power off sequence . The RTC
* generates pmic_pwr_enable control , which can be used to control an external
* PMIC .
2014-12-11 02:53:13 +03:00
*/
2019-04-03 07:57:39 +03:00
int omap_rtc_power_off_program ( struct device * dev )
2014-12-11 02:53:13 +03:00
{
struct omap_rtc * rtc = omap_rtc_power_off_rtc ;
struct rtc_time tm ;
unsigned long now ;
2018-08-16 08:09:00 +03:00
int seconds ;
2014-12-11 02:53:13 +03:00
u32 val ;
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-12-11 02:53:13 +03:00
/* enable pmic_power_en control */
val = rtc_readl ( rtc , OMAP_RTC_PMIC_REG ) ;
rtc_writel ( rtc , OMAP_RTC_PMIC_REG , val | OMAP_RTC_PMIC_POWER_EN_EN ) ;
2018-08-16 08:09:00 +03:00
again :
2019-04-03 07:57:39 +03:00
/* Clear any existing ALARM2 event */
rtc_writel ( rtc , OMAP_RTC_STATUS_REG , OMAP_RTC_STATUS_ALARM2 ) ;
2018-08-16 08:09:00 +03:00
/* set alarm one second from now */
2014-12-11 02:53:13 +03:00
omap_rtc_read_time_raw ( rtc , & tm ) ;
2018-08-16 08:09:00 +03:00
seconds = tm . tm_sec ;
2014-12-11 02:53:13 +03:00
bcd2tm ( & tm ) ;
2019-03-18 16:26:08 +03:00
now = rtc_tm_to_time64 ( & tm ) ;
rtc_time64_to_tm ( now + 1 , & tm ) ;
2014-12-11 02:53:13 +03:00
2019-03-18 15:44:38 +03:00
tm2bcd ( & tm ) ;
2014-12-11 02:53:13 +03:00
rtc_wait_not_busy ( rtc ) ;
rtc_write ( rtc , OMAP_RTC_ALARM2_SECONDS_REG , tm . tm_sec ) ;
rtc_write ( rtc , OMAP_RTC_ALARM2_MINUTES_REG , tm . tm_min ) ;
rtc_write ( rtc , OMAP_RTC_ALARM2_HOURS_REG , tm . tm_hour ) ;
rtc_write ( rtc , OMAP_RTC_ALARM2_DAYS_REG , tm . tm_mday ) ;
rtc_write ( rtc , OMAP_RTC_ALARM2_MONTHS_REG , tm . tm_mon ) ;
rtc_write ( rtc , OMAP_RTC_ALARM2_YEARS_REG , tm . tm_year ) ;
/*
* enable ALARM2 interrupt
*
* NOTE : this fails on AM3352 if rtc_write ( writeb ) is used
*/
val = rtc_read ( rtc , OMAP_RTC_INTERRUPTS_REG ) ;
rtc_writel ( rtc , OMAP_RTC_INTERRUPTS_REG ,
val | OMAP_RTC_INTERRUPTS_IT_ALARM2 ) ;
2018-08-16 08:09:00 +03:00
/* Retry in case roll over happened before alarm was armed. */
if ( rtc_read ( rtc , OMAP_RTC_SECONDS_REG ) ! = seconds ) {
val = rtc_read ( rtc , OMAP_RTC_STATUS_REG ) ;
if ( ! ( val & OMAP_RTC_STATUS_ALARM2 ) )
goto again ;
}
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2014-12-11 02:53:13 +03:00
2019-04-03 07:57:39 +03:00
return 0 ;
}
EXPORT_SYMBOL ( omap_rtc_power_off_program ) ;
/*
* omap_rtc_poweroff : RTC - controlled power off
*
* The RTC can be used to control an external PMIC via the pmic_power_en pin ,
* which can be configured to transition to OFF on ALARM2 events .
*
* Notes :
* The one - second alarm offset is the shortest offset possible as the alarm
* registers must be set before the next timer update and the offset
* calculation is too heavy for everything to be done within a single access
* period ( ~ 15 us ) .
*
* Called with local interrupts disabled .
*/
static void omap_rtc_power_off ( void )
{
struct rtc_device * rtc = omap_rtc_power_off_rtc - > rtc ;
u32 val ;
omap_rtc_power_off_program ( rtc - > dev . parent ) ;
/* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */
omap_rtc_power_off_rtc - > type - > unlock ( omap_rtc_power_off_rtc ) ;
val = rtc_readl ( omap_rtc_power_off_rtc , OMAP_RTC_PMIC_REG ) ;
val | = OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL ( 0 ) |
OMAP_RTC_PMIC_EXT_WKUP_EN ( 0 ) ;
rtc_writel ( omap_rtc_power_off_rtc , OMAP_RTC_PMIC_REG , val ) ;
omap_rtc_power_off_rtc - > type - > lock ( omap_rtc_power_off_rtc ) ;
2014-12-11 02:53:13 +03:00
/*
2018-08-16 08:09:00 +03:00
* Wait for alarm to trigger ( within one second ) and external PMIC to
2014-12-11 02:53:13 +03:00
* power off the system . Add a 500 ms margin for external latencies
* ( e . g . debounce circuits ) .
*/
2018-08-16 08:09:00 +03:00
mdelay ( 1500 ) ;
2014-12-11 02:53:13 +03:00
}
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 omap_rtc_ops = {
2006-12-07 07:38:36 +03:00
. read_time = omap_rtc_read_time ,
. set_time = omap_rtc_set_time ,
. read_alarm = omap_rtc_read_alarm ,
. set_alarm = omap_rtc_set_alarm ,
2011-02-03 04:02:41 +03:00
. alarm_irq_enable = omap_rtc_alarm_irq_enable ,
2006-12-07 07:38:36 +03:00
} ;
2014-12-11 02:53:01 +03:00
static const struct omap_rtc_device_type omap_rtc_default_type = {
2014-12-11 02:53:04 +03:00
. has_power_up_reset = true ,
2015-04-16 22:46:00 +03:00
. lock = default_rtc_lock ,
. unlock = default_rtc_unlock ,
2014-12-11 02:53:01 +03:00
} ;
static const struct omap_rtc_device_type omap_rtc_am3352_type = {
. has_32kclk_en = true ,
. has_irqwakeen = true ,
2014-12-11 02:53:13 +03:00
. has_pmic_mode = true ,
2015-04-16 22:46:00 +03:00
. lock = am3352_rtc_lock ,
. unlock = am3352_rtc_unlock ,
2014-12-11 02:53:01 +03:00
} ;
static const struct omap_rtc_device_type omap_rtc_da830_type = {
2015-04-16 22:46:00 +03:00
. lock = am3352_rtc_lock ,
. unlock = am3352_rtc_unlock ,
2014-12-11 02:53:01 +03:00
} ;
2012-12-18 04:02:15 +04:00
2014-12-11 02:53:01 +03:00
static const struct platform_device_id omap_rtc_id_table [ ] = {
2012-12-18 04:02:11 +04:00
{
2014-12-11 02:52:58 +03:00
. name = " omap_rtc " ,
2014-12-11 02:53:01 +03:00
. driver_data = ( kernel_ulong_t ) & omap_rtc_default_type ,
} , {
2013-09-12 01:24:18 +04:00
. name = " am3352-rtc " ,
2014-12-11 02:53:01 +03:00
. driver_data = ( kernel_ulong_t ) & omap_rtc_am3352_type ,
} , {
2012-12-18 04:02:11 +04:00
. name = " da830-rtc " ,
2014-12-11 02:53:01 +03:00
. driver_data = ( kernel_ulong_t ) & omap_rtc_da830_type ,
} , {
/* sentinel */
}
2012-12-18 04:02:11 +04:00
} ;
2014-12-11 02:53:01 +03:00
MODULE_DEVICE_TABLE ( platform , omap_rtc_id_table ) ;
2012-12-18 04:02:11 +04:00
2012-12-18 04:02:15 +04:00
static const struct of_device_id omap_rtc_of_match [ ] = {
2014-12-11 02:53:01 +03:00
{
. compatible = " ti,am3352-rtc " ,
. data = & omap_rtc_am3352_type ,
} , {
. compatible = " ti,da830-rtc " ,
. data = & omap_rtc_da830_type ,
} , {
/* sentinel */
}
2012-12-18 04:02:15 +04:00
} ;
MODULE_DEVICE_TABLE ( of , omap_rtc_of_match ) ;
2016-09-16 12:26:28 +03:00
static const struct pinctrl_pin_desc rtc_pins_desc [ ] = {
PINCTRL_PIN ( 0 , " ext_wakeup0 " ) ,
PINCTRL_PIN ( 1 , " ext_wakeup1 " ) ,
PINCTRL_PIN ( 2 , " ext_wakeup2 " ) ,
PINCTRL_PIN ( 3 , " ext_wakeup3 " ) ,
} ;
static int rtc_pinctrl_get_groups_count ( struct pinctrl_dev * pctldev )
{
return 0 ;
}
static const char * rtc_pinctrl_get_group_name ( struct pinctrl_dev * pctldev ,
unsigned int group )
{
return NULL ;
}
static const struct pinctrl_ops rtc_pinctrl_ops = {
. get_groups_count = rtc_pinctrl_get_groups_count ,
. get_group_name = rtc_pinctrl_get_group_name ,
. dt_node_to_map = pinconf_generic_dt_node_to_map_pin ,
. dt_free_map = pinconf_generic_dt_free_map ,
} ;
rtc: omap: Use define directive for PIN_CONFIG_ACTIVE_HIGH
Clang warns when one enumerated type is implicitly converted to another:
drivers/rtc/rtc-omap.c:574:21: warning: implicit conversion from
enumeration type 'enum rtc_pin_config_param' to different enumeration
type 'enum pin_config_param' [-Wenum-conversion]
{"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0},
~ ^~~~~~~~~~~~~~~~~~~~~~
drivers/rtc/rtc-omap.c:579:12: warning: implicit conversion from
enumeration type 'enum rtc_pin_config_param' to different enumeration
type 'enum pin_config_param' [-Wenum-conversion]
PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false),
~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./include/linux/pinctrl/pinconf-generic.h:163:11: note: expanded from
macro 'PCONFDUMP'
.param = a, .display = b, .format = c, .has_arg = d \
^
2 warnings generated.
It is expected that pinctrl drivers can extend pin_config_param because
of the gap between PIN_CONFIG_END and PIN_CONFIG_MAX so this conversion
isn't an issue. Most drivers that take advantage of this define the
PIN_CONFIG variables as constants, rather than enumerated values. Do the
same thing here so that Clang no longer warns.
Link: https://github.com/ClangBuiltLinux/linux/issues/144
Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
2018-11-01 03:55:02 +03:00
# define PIN_CONFIG_ACTIVE_HIGH (PIN_CONFIG_END + 1)
2016-09-16 12:26:28 +03:00
static const struct pinconf_generic_params rtc_params [ ] = {
{ " ti,active-high " , PIN_CONFIG_ACTIVE_HIGH , 0 } ,
} ;
# ifdef CONFIG_DEBUG_FS
static const struct pin_config_item rtc_conf_items [ ARRAY_SIZE ( rtc_params ) ] = {
PCONFDUMP ( PIN_CONFIG_ACTIVE_HIGH , " input active high " , NULL , false ) ,
} ;
# endif
static int rtc_pinconf_get ( struct pinctrl_dev * pctldev ,
unsigned int pin , unsigned long * config )
{
struct omap_rtc * rtc = pinctrl_dev_get_drvdata ( pctldev ) ;
unsigned int param = pinconf_to_config_param ( * config ) ;
u32 val ;
u16 arg = 0 ;
val = rtc_readl ( rtc , OMAP_RTC_PMIC_REG ) ;
switch ( param ) {
case PIN_CONFIG_INPUT_ENABLE :
if ( ! ( val & OMAP_RTC_PMIC_EXT_WKUP_EN ( pin ) ) )
return - EINVAL ;
break ;
case PIN_CONFIG_ACTIVE_HIGH :
if ( val & OMAP_RTC_PMIC_EXT_WKUP_POL ( pin ) )
return - EINVAL ;
break ;
default :
return - ENOTSUPP ;
2019-12-16 06:19:13 +03:00
}
2016-09-16 12:26:28 +03:00
* config = pinconf_to_config_packed ( param , arg ) ;
return 0 ;
}
static int rtc_pinconf_set ( struct pinctrl_dev * pctldev ,
unsigned int pin , unsigned long * configs ,
unsigned int num_configs )
{
struct omap_rtc * rtc = pinctrl_dev_get_drvdata ( pctldev ) ;
u32 val ;
unsigned int param ;
2017-01-23 15:34:32 +03:00
u32 param_val ;
2016-09-16 12:26:28 +03:00
int i ;
val = rtc_readl ( rtc , OMAP_RTC_PMIC_REG ) ;
/* active low by default */
val | = OMAP_RTC_PMIC_EXT_WKUP_POL ( pin ) ;
for ( i = 0 ; i < num_configs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
param_val = pinconf_to_config_argument ( configs [ i ] ) ;
switch ( param ) {
case PIN_CONFIG_INPUT_ENABLE :
if ( param_val )
val | = OMAP_RTC_PMIC_EXT_WKUP_EN ( pin ) ;
else
val & = ~ OMAP_RTC_PMIC_EXT_WKUP_EN ( pin ) ;
break ;
case PIN_CONFIG_ACTIVE_HIGH :
val & = ~ OMAP_RTC_PMIC_EXT_WKUP_POL ( pin ) ;
break ;
default :
dev_err ( & rtc - > rtc - > dev , " Property %u not supported \n " ,
param ) ;
return - ENOTSUPP ;
}
}
rtc - > type - > unlock ( rtc ) ;
rtc_writel ( rtc , OMAP_RTC_PMIC_REG , val ) ;
rtc - > type - > lock ( rtc ) ;
return 0 ;
}
static const struct pinconf_ops rtc_pinconf_ops = {
. is_generic = true ,
. pin_config_get = rtc_pinconf_get ,
. pin_config_set = rtc_pinconf_set ,
} ;
static struct pinctrl_desc rtc_pinctrl_desc = {
. pins = rtc_pins_desc ,
. npins = ARRAY_SIZE ( rtc_pins_desc ) ,
. pctlops = & rtc_pinctrl_ops ,
. confops = & rtc_pinconf_ops ,
. custom_params = rtc_params ,
. num_custom_params = ARRAY_SIZE ( rtc_params ) ,
# ifdef CONFIG_DEBUG_FS
. custom_conf_items = rtc_conf_items ,
# endif
. owner = THIS_MODULE ,
} ;
2017-10-31 19:27:31 +03:00
static int omap_rtc_scratch_read ( void * priv , unsigned int offset , void * _val ,
size_t bytes )
{
struct omap_rtc * rtc = priv ;
u32 * val = _val ;
int i ;
for ( i = 0 ; i < bytes / 4 ; i + + )
val [ i ] = rtc_readl ( rtc ,
OMAP_RTC_SCRATCH0_REG + offset + ( i * 4 ) ) ;
return 0 ;
}
static int omap_rtc_scratch_write ( void * priv , unsigned int offset , void * _val ,
size_t bytes )
{
struct omap_rtc * rtc = priv ;
u32 * val = _val ;
int i ;
rtc - > type - > unlock ( rtc ) ;
for ( i = 0 ; i < bytes / 4 ; i + + )
rtc_writel ( rtc ,
OMAP_RTC_SCRATCH0_REG + offset + ( i * 4 ) , val [ i ] ) ;
rtc - > type - > lock ( rtc ) ;
return 0 ;
}
static struct nvmem_config omap_rtc_nvmem_config = {
. name = " omap_rtc_scratch " ,
. word_size = 4 ,
. stride = 4 ,
. size = OMAP_RTC_KICK0_REG - OMAP_RTC_SCRATCH0_REG ,
. reg_read = omap_rtc_scratch_read ,
. reg_write = omap_rtc_scratch_write ,
} ;
2015-04-16 22:46:05 +03:00
static int omap_rtc_probe ( struct platform_device * pdev )
2006-12-07 07:38:36 +03:00
{
2014-12-11 02:53:19 +03:00
struct omap_rtc * rtc ;
u8 reg , mask , new_ctrl ;
2012-12-18 04:02:11 +04:00
const struct platform_device_id * id_entry ;
2012-12-18 04:02:15 +04:00
const struct of_device_id * of_id ;
2014-12-11 02:52:40 +03:00
int ret ;
2012-12-18 04:02:15 +04:00
2014-12-11 02:52:55 +03:00
rtc = devm_kzalloc ( & pdev - > dev , sizeof ( * rtc ) , GFP_KERNEL ) ;
if ( ! rtc )
return - ENOMEM ;
2012-12-18 04:02:15 +04:00
of_id = of_match_device ( omap_rtc_of_match , & pdev - > dev ) ;
2014-12-11 02:53:01 +03:00
if ( of_id ) {
rtc - > type = of_id - > data ;
2014-12-11 02:53:13 +03:00
rtc - > is_pmic_controller = rtc - > type - > has_pmic_mode & &
2018-08-16 08:08:59 +03:00
of_device_is_system_power_controller ( pdev - > dev . of_node ) ;
2014-12-11 02:53:01 +03:00
} else {
id_entry = platform_get_device_id ( pdev ) ;
rtc - > type = ( void * ) id_entry - > driver_data ;
2014-06-07 01:36:04 +04:00
}
2014-12-11 02:52:55 +03:00
rtc - > irq_timer = platform_get_irq ( pdev , 0 ) ;
if ( rtc - > irq_timer < = 0 )
2006-12-07 07:38:36 +03:00
return - ENOENT ;
2014-12-11 02:52:55 +03:00
rtc - > irq_alarm = platform_get_irq ( pdev , 1 ) ;
if ( rtc - > irq_alarm < = 0 )
2006-12-07 07:38:36 +03:00
return - ENOENT ;
2015-08-18 12:41:16 +03:00
rtc - > clk = devm_clk_get ( & pdev - > dev , " ext-clk " ) ;
if ( ! IS_ERR ( rtc - > clk ) )
rtc - > has_ext_clk = true ;
else
rtc - > clk = devm_clk_get ( & pdev - > dev , " int-clk " ) ;
2015-08-18 12:41:15 +03:00
if ( ! IS_ERR ( rtc - > clk ) )
clk_prepare_enable ( rtc - > clk ) ;
2019-10-06 13:29:20 +03:00
rtc - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2017-12-06 22:42:38 +03:00
if ( IS_ERR ( rtc - > base ) ) {
clk_disable_unprepare ( rtc - > clk ) ;
2014-12-11 02:52:55 +03:00
return PTR_ERR ( rtc - > base ) ;
2017-12-06 22:42:38 +03:00
}
2014-12-11 02:52:55 +03:00
platform_set_drvdata ( pdev , rtc ) ;
2009-12-16 03:46:11 +03:00
2012-12-18 04:02:18 +04:00
/* Enable the clock/module so that we can access the registers */
pm_runtime_enable ( & pdev - > dev ) ;
pm_runtime_get_sync ( & pdev - > dev ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2012-12-18 04:02:11 +04:00
2014-12-11 02:52:36 +03:00
/*
* disable interrupts
*
* NOTE : ALARM2 is not cleared on AM3352 if rtc_write ( writeb ) is used
2006-12-07 07:38:36 +03:00
*/
2014-12-11 02:52:55 +03:00
rtc_writel ( rtc , OMAP_RTC_INTERRUPTS_REG , 0 ) ;
2006-12-07 07:38:36 +03:00
2014-06-07 01:36:06 +04:00
/* enable RTC functional clock */
2014-12-11 02:53:01 +03:00
if ( rtc - > type - > has_32kclk_en ) {
2014-12-11 02:52:55 +03:00
reg = rtc_read ( rtc , OMAP_RTC_OSC_REG ) ;
rtc_writel ( rtc , OMAP_RTC_OSC_REG ,
reg | OMAP_RTC_OSC_32KCLK_EN ) ;
2014-12-11 02:52:30 +03:00
}
2014-06-07 01:36:06 +04:00
2006-12-07 07:38:36 +03:00
/* clear old status */
2014-12-11 02:52:55 +03:00
reg = rtc_read ( rtc , OMAP_RTC_STATUS_REG ) ;
2014-12-11 02:53:04 +03:00
mask = OMAP_RTC_STATUS_ALARM ;
2014-12-11 02:53:13 +03:00
if ( rtc - > type - > has_pmic_mode )
mask | = OMAP_RTC_STATUS_ALARM2 ;
2014-12-11 02:53:04 +03:00
if ( rtc - > type - > has_power_up_reset ) {
mask | = OMAP_RTC_STATUS_POWER_UP ;
if ( reg & OMAP_RTC_STATUS_POWER_UP )
dev_info ( & pdev - > dev , " RTC power up reset detected \n " ) ;
2006-12-07 07:38:36 +03:00
}
2014-12-11 02:53:04 +03:00
if ( reg & mask )
rtc_write ( rtc , OMAP_RTC_STATUS_REG , reg & mask ) ;
2006-12-07 07:38:36 +03:00
/* On boards with split power, RTC_ON_NOFF won't reset the RTC */
2014-12-11 02:52:55 +03:00
reg = rtc_read ( rtc , OMAP_RTC_CTRL_REG ) ;
2014-12-11 02:53:19 +03:00
if ( reg & OMAP_RTC_CTRL_STOP )
2014-12-11 02:52:49 +03:00
dev_info ( & pdev - > dev , " already running \n " ) ;
2006-12-07 07:38:36 +03:00
/* force to 24 hour mode */
2014-12-11 02:53:19 +03:00
new_ctrl = reg & ( OMAP_RTC_CTRL_SPLIT | OMAP_RTC_CTRL_AUTO_COMP ) ;
2006-12-07 07:38:36 +03:00
new_ctrl | = OMAP_RTC_CTRL_STOP ;
2014-12-11 02:53:19 +03:00
/*
* BOARD - SPECIFIC CUSTOMIZATION CAN GO HERE :
2006-12-07 07:38:36 +03:00
*
2010-10-28 02:33:05 +04:00
* - Device wake - up capability setting should come through chip
* init logic . OMAP1 boards should initialize the " wakeup capable "
* flag in the platform device if the board is wired right for
* being woken up by RTC alarm . For OMAP - L138 , this capability
* is built into the SoC by the " Deep Sleep " capability .
2006-12-07 07:38:36 +03:00
*
* - Boards wired so RTC_ON_nOFF is used as the reset signal ,
* rather than nPWRON_RESET , should forcibly enable split
* power mode . ( Some chip errata report that RTC_CTRL_SPLIT
* is write - only , and always reads as zero . . . )
*/
2014-12-11 02:53:19 +03:00
if ( new_ctrl & OMAP_RTC_CTRL_SPLIT )
2014-12-11 02:52:49 +03:00
dev_info ( & pdev - > dev , " split power mode \n " ) ;
2006-12-07 07:38:36 +03:00
if ( reg ! = new_ctrl )
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_CTRL_REG , new_ctrl ) ;
2006-12-07 07:38:36 +03:00
2015-08-18 12:41:16 +03:00
/*
* If we have the external clock then switch to it so we can keep
* ticking across suspend .
*/
if ( rtc - > has_ext_clk ) {
reg = rtc_read ( rtc , OMAP_RTC_OSC_REG ) ;
2016-10-27 08:57:25 +03:00
reg & = ~ OMAP_RTC_OSC_OSC32K_GZ_DISABLE ;
reg | = OMAP_RTC_OSC_32KCLK_EN | OMAP_RTC_OSC_SEL_32KCLK_SRC ;
rtc_writel ( rtc , OMAP_RTC_OSC_REG , reg ) ;
2015-08-18 12:41:16 +03:00
}
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2014-12-11 02:52:43 +03:00
device_init_wakeup ( & pdev - > dev , true ) ;
2017-10-13 01:06:45 +03:00
rtc - > rtc = devm_rtc_allocate_device ( & pdev - > dev ) ;
2014-12-11 02:52:55 +03:00
if ( IS_ERR ( rtc - > rtc ) ) {
ret = PTR_ERR ( rtc - > rtc ) ;
2014-12-11 02:52:43 +03:00
goto err ;
}
2017-10-13 01:06:45 +03:00
rtc - > rtc - > ops = & omap_rtc_ops ;
2019-03-18 15:44:38 +03:00
rtc - > rtc - > range_min = RTC_TIMESTAMP_BEGIN_2000 ;
rtc - > rtc - > range_max = RTC_TIMESTAMP_END_2099 ;
2017-10-31 19:27:31 +03:00
omap_rtc_nvmem_config . priv = rtc ;
2017-10-13 01:06:45 +03:00
2014-12-11 02:52:43 +03:00
/* handle periodic and alarm irqs */
2014-12-11 02:52:55 +03:00
ret = devm_request_irq ( & pdev - > dev , rtc - > irq_timer , rtc_irq , 0 ,
dev_name ( & rtc - > rtc - > dev ) , rtc ) ;
2014-12-11 02:52:43 +03:00
if ( ret )
goto err ;
2014-12-11 02:52:55 +03:00
if ( rtc - > irq_timer ! = rtc - > irq_alarm ) {
ret = devm_request_irq ( & pdev - > dev , rtc - > irq_alarm , rtc_irq , 0 ,
dev_name ( & rtc - > rtc - > dev ) , rtc ) ;
2014-12-11 02:52:43 +03:00
if ( ret )
goto err ;
}
2016-09-16 12:26:28 +03:00
/* Support ext_wakeup pinconf */
rtc_pinctrl_desc . name = dev_name ( & pdev - > dev ) ;
rtc - > pctldev = pinctrl_register ( & rtc_pinctrl_desc , & pdev - > dev , rtc ) ;
if ( IS_ERR ( rtc - > pctldev ) ) {
dev_err ( & pdev - > dev , " Couldn't register pinctrl driver \n " ) ;
2017-10-13 01:06:44 +03:00
ret = PTR_ERR ( rtc - > pctldev ) ;
goto err ;
2016-09-16 12:26:28 +03:00
}
2017-10-13 01:06:45 +03:00
ret = rtc_register_device ( rtc - > rtc ) ;
if ( ret )
2018-07-04 12:05:56 +03:00
goto err_deregister_pinctrl ;
2017-10-13 01:06:45 +03:00
2018-02-13 01:47:28 +03:00
rtc_nvmem_register ( rtc - > rtc , & omap_rtc_nvmem_config ) ;
2018-07-04 12:05:55 +03:00
if ( rtc - > is_pmic_controller ) {
if ( ! pm_power_off ) {
omap_rtc_power_off_rtc = rtc ;
pm_power_off = omap_rtc_power_off ;
}
}
2006-12-07 07:38:36 +03:00
return 0 ;
2018-07-04 12:05:56 +03:00
err_deregister_pinctrl :
pinctrl_unregister ( rtc - > pctldev ) ;
2014-12-11 02:52:40 +03:00
err :
2017-12-06 22:42:38 +03:00
clk_disable_unprepare ( rtc - > clk ) ;
2014-12-11 02:52:33 +03:00
device_init_wakeup ( & pdev - > dev , false ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2012-12-18 04:02:18 +04:00
pm_runtime_put_sync ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2014-12-11 02:52:40 +03:00
return ret ;
2006-12-07 07:38:36 +03:00
}
2017-03-02 02:33:23 +03:00
static int omap_rtc_remove ( struct platform_device * pdev )
2006-12-07 07:38:36 +03:00
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = platform_get_drvdata ( pdev ) ;
2015-08-18 12:41:16 +03:00
u8 reg ;
2006-12-07 07:38:36 +03:00
2014-12-11 02:53:13 +03:00
if ( pm_power_off = = omap_rtc_power_off & &
omap_rtc_power_off_rtc = = rtc ) {
pm_power_off = NULL ;
omap_rtc_power_off_rtc = NULL ;
}
2006-12-07 07:38:36 +03:00
device_init_wakeup ( & pdev - > dev , 0 ) ;
2015-08-18 12:41:15 +03:00
if ( ! IS_ERR ( rtc - > clk ) )
clk_disable_unprepare ( rtc - > clk ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2006-12-07 07:38:36 +03:00
/* leave rtc running, but disable irqs */
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_INTERRUPTS_REG , 0 ) ;
2006-12-07 07:38:36 +03:00
2015-08-18 12:41:16 +03:00
if ( rtc - > has_ext_clk ) {
reg = rtc_read ( rtc , OMAP_RTC_OSC_REG ) ;
reg & = ~ OMAP_RTC_OSC_SEL_32KCLK_SRC ;
rtc_write ( rtc , OMAP_RTC_OSC_REG , reg ) ;
}
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2012-12-18 04:02:18 +04:00
/* Disable the clock/module */
pm_runtime_put_sync ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2016-09-16 12:26:28 +03:00
/* Remove ext_wakeup pinconf */
pinctrl_unregister ( rtc - > pctldev ) ;
2006-12-07 07:38:36 +03:00
return 0 ;
}
2017-03-02 02:34:38 +03:00
static int __maybe_unused omap_rtc_suspend ( struct device * dev )
2006-12-07 07:38:36 +03:00
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
rtc - > interrupts_reg = rtc_read ( rtc , OMAP_RTC_INTERRUPTS_REG ) ;
2006-12-07 07:38:36 +03:00
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-12-11 02:53:19 +03:00
/*
* FIXME : the RTC alarm is not currently acting as a wakeup event
2013-09-12 01:24:18 +04:00
* source on some platforms , and in fact this enable ( ) call is just
* saving a flag that ' s never used . . .
2006-12-07 07:38:36 +03:00
*/
2014-06-07 01:36:12 +04:00
if ( device_may_wakeup ( dev ) )
2014-12-11 02:52:55 +03:00
enable_irq_wake ( rtc - > irq_alarm ) ;
2014-06-07 01:36:12 +04:00
else
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_INTERRUPTS_REG , 0 ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2006-12-07 07:38:36 +03:00
2016-10-27 08:57:26 +03:00
rtc - > is_suspending = true ;
2012-12-18 04:02:18 +04:00
2006-12-07 07:38:36 +03:00
return 0 ;
}
2017-03-02 02:34:38 +03:00
static int __maybe_unused omap_rtc_resume ( struct device * dev )
2006-12-07 07:38:36 +03:00
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-06-07 01:36:12 +04:00
if ( device_may_wakeup ( dev ) )
2014-12-11 02:52:55 +03:00
disable_irq_wake ( rtc - > irq_alarm ) ;
2014-06-07 01:36:12 +04:00
else
2014-12-11 02:52:55 +03:00
rtc_write ( rtc , OMAP_RTC_INTERRUPTS_REG , rtc - > interrupts_reg ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2014-06-07 01:36:12 +04:00
2016-10-27 08:57:26 +03:00
rtc - > is_suspending = false ;
2006-12-07 07:38:36 +03:00
return 0 ;
}
2017-03-02 02:34:38 +03:00
static int __maybe_unused omap_rtc_runtime_suspend ( struct device * dev )
2016-10-27 08:57:26 +03:00
{
struct omap_rtc * rtc = dev_get_drvdata ( dev ) ;
if ( rtc - > is_suspending & & ! rtc - > has_ext_clk )
return - EBUSY ;
return 0 ;
}
static const struct dev_pm_ops omap_rtc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( omap_rtc_suspend , omap_rtc_resume )
2017-03-02 02:34:38 +03:00
SET_RUNTIME_PM_OPS ( omap_rtc_runtime_suspend , NULL , NULL )
2016-10-27 08:57:26 +03:00
} ;
2013-04-30 03:21:01 +04:00
2006-12-07 07:38:36 +03:00
static void omap_rtc_shutdown ( struct platform_device * pdev )
{
2014-12-11 02:52:55 +03:00
struct omap_rtc * rtc = platform_get_drvdata ( pdev ) ;
2014-12-11 02:53:16 +03:00
u8 mask ;
2014-12-11 02:52:55 +03:00
2014-12-11 02:53:16 +03:00
/*
* Keep the ALARM interrupt enabled to allow the system to power up on
* alarm events .
*/
2015-04-16 22:46:00 +03:00
rtc - > type - > unlock ( rtc ) ;
2014-12-11 02:53:16 +03:00
mask = rtc_read ( rtc , OMAP_RTC_INTERRUPTS_REG ) ;
mask & = OMAP_RTC_INTERRUPTS_IT_ALARM ;
rtc_write ( rtc , OMAP_RTC_INTERRUPTS_REG , mask ) ;
2015-04-16 22:46:00 +03:00
rtc - > type - > lock ( rtc ) ;
2006-12-07 07:38:36 +03:00
}
static struct platform_driver omap_rtc_driver = {
2015-04-16 22:46:05 +03:00
. probe = omap_rtc_probe ,
2017-03-02 02:33:23 +03:00
. remove = omap_rtc_remove ,
2006-12-07 07:38:36 +03:00
. shutdown = omap_rtc_shutdown ,
. driver = {
2014-12-11 02:52:58 +03:00
. name = " omap_rtc " ,
2013-04-30 03:21:01 +04:00
. pm = & omap_rtc_pm_ops ,
2013-11-13 03:10:55 +04:00
. of_match_table = omap_rtc_of_match ,
2006-12-07 07:38:36 +03:00
} ,
2014-12-11 02:53:01 +03:00
. id_table = omap_rtc_id_table ,
2006-12-07 07:38:36 +03:00
} ;
2015-04-16 22:46:05 +03:00
module_platform_driver ( omap_rtc_driver ) ;
2006-12-07 07:38:36 +03:00
2014-12-11 02:52:58 +03:00
MODULE_ALIAS ( " platform:omap_rtc " ) ;
2006-12-07 07:38:36 +03:00
MODULE_AUTHOR ( " George G. Davis (and others) " ) ;
MODULE_LICENSE ( " GPL " ) ;