Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
L
linux
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Model registry
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Tomeu Vizoso
linux
Commits
2a471bf4
Commit
2a471bf4
authored
7 years ago
by
Stephen Rothwell
Browse files
Options
Downloads
Plain Diff
Merge remote-tracking branch 'rtc/rtc-next'
parents
5a6f49b2
36d91a4d
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
drivers/rtc/rtc-cmos.c
+124
-31
124 additions, 31 deletions
drivers/rtc/rtc-cmos.c
with
124 additions
and
31 deletions
drivers/rtc/rtc-cmos.c
+
124
−
31
View file @
2a471bf4
...
...
@@ -43,11 +43,24 @@
#include
<linux/of_platform.h>
#ifdef CONFIG_X86
#include
<asm/i8259.h>
#include
<asm/processor.h>
#include
<linux/dmi.h>
#endif
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
#include
<linux/mc146818rtc.h>
/*
* Use ACPI SCI to replace HPET interrupt for RTC Alarm event
*
* If cleared, ACPI SCI is only used to wake up the system from suspend
*
* If set, ACPI SCI is used to handle UIE/AIE and system wakeup
*/
static
bool
use_acpi_alarm
;
module_param
(
use_acpi_alarm
,
bool
,
0444
);
struct
cmos_rtc
{
struct
rtc_device
*
rtc
;
struct
device
*
dev
;
...
...
@@ -153,6 +166,12 @@ static inline int hpet_unregister_irq_handler(irq_handler_t handler)
#endif
/* Don't use HPET for RTC Alarm event if ACPI Fixed event is used */
static
int
use_hpet_alarm
(
void
)
{
return
is_hpet_enabled
()
&&
!
use_acpi_alarm
;
}
/*----------------------------------------------------------------*/
#ifdef RTC_PORT
...
...
@@ -298,7 +317,7 @@ static void cmos_checkintr(struct cmos_rtc *cmos, unsigned char rtc_control)
*/
rtc_intr
=
CMOS_READ
(
RTC_INTR_FLAGS
);
if
(
is
_hpet_
enabled
())
if
(
use
_hpet_
alarm
())
return
;
rtc_intr
&=
(
rtc_control
&
RTC_IRQMASK
)
|
RTC_IRQF
;
...
...
@@ -318,7 +337,13 @@ static void cmos_irq_enable(struct cmos_rtc *cmos, unsigned char mask)
rtc_control
|=
mask
;
CMOS_WRITE
(
rtc_control
,
RTC_CONTROL
);
hpet_set_rtc_irq_bit
(
mask
);
if
(
use_hpet_alarm
())
hpet_set_rtc_irq_bit
(
mask
);
if
((
mask
&
RTC_AIE
)
&&
use_acpi_alarm
)
{
if
(
cmos
->
wake_on
)
cmos
->
wake_on
(
cmos
->
dev
);
}
cmos_checkintr
(
cmos
,
rtc_control
);
}
...
...
@@ -330,7 +355,13 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
rtc_control
=
CMOS_READ
(
RTC_CONTROL
);
rtc_control
&=
~
mask
;
CMOS_WRITE
(
rtc_control
,
RTC_CONTROL
);
hpet_mask_rtc_irq_bit
(
mask
);
if
(
use_hpet_alarm
())
hpet_mask_rtc_irq_bit
(
mask
);
if
((
mask
&
RTC_AIE
)
&&
use_acpi_alarm
)
{
if
(
cmos
->
wake_off
)
cmos
->
wake_off
(
cmos
->
dev
);
}
cmos_checkintr
(
cmos
,
rtc_control
);
}
...
...
@@ -448,10 +479,14 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
CMOS_WRITE
(
mon
,
cmos
->
mon_alrm
);
}
/* FIXME the HPET alarm glue currently ignores day_alrm
* and mon_alrm ...
*/
hpet_set_alarm_time
(
t
->
time
.
tm_hour
,
t
->
time
.
tm_min
,
t
->
time
.
tm_sec
);
if
(
use_hpet_alarm
())
{
/*
* FIXME the HPET alarm glue currently ignores day_alrm
* and mon_alrm ...
*/
hpet_set_alarm_time
(
t
->
time
.
tm_hour
,
t
->
time
.
tm_min
,
t
->
time
.
tm_sec
);
}
if
(
t
->
enabled
)
cmos_irq_enable
(
cmos
,
RTC_AIE
);
...
...
@@ -508,7 +543,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
"batt_status
\t
: %s
\n
"
,
(
rtc_control
&
RTC_PIE
)
?
"yes"
:
"no"
,
(
rtc_control
&
RTC_UIE
)
?
"yes"
:
"no"
,
is
_hpet_
enabled
()
?
"yes"
:
"no"
,
use
_hpet_
alarm
()
?
"yes"
:
"no"
,
// (rtc_control & RTC_SQWE) ? "yes" : "no",
(
rtc_control
&
RTC_DM_BINARY
)
?
"no"
:
"yes"
,
(
rtc_control
&
RTC_DST_EN
)
?
"yes"
:
"no"
,
...
...
@@ -614,7 +649,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
*/
irqstat
=
CMOS_READ
(
RTC_INTR_FLAGS
);
rtc_control
=
CMOS_READ
(
RTC_CONTROL
);
if
(
is
_hpet_
enabled
())
if
(
use
_hpet_
alarm
())
irqstat
=
(
unsigned
long
)
irq
&
0xF0
;
/* If we were suspended, RTC_CONTROL may not be accurate since the
...
...
@@ -633,7 +668,8 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
cmos_rtc
.
suspend_ctrl
&=
~
RTC_AIE
;
rtc_control
&=
~
RTC_AIE
;
CMOS_WRITE
(
rtc_control
,
RTC_CONTROL
);
hpet_mask_rtc_irq_bit
(
RTC_AIE
);
if
(
use_hpet_alarm
())
hpet_mask_rtc_irq_bit
(
RTC_AIE
);
CMOS_READ
(
RTC_INTR_FLAGS
);
}
spin_unlock
(
&
rtc_lock
);
...
...
@@ -762,7 +798,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* need to do something about other clock frequencies.
*/
cmos_rtc
.
rtc
->
irq_freq
=
1024
;
hpet_set_periodic_freq
(
cmos_rtc
.
rtc
->
irq_freq
);
if
(
use_hpet_alarm
())
hpet_set_periodic_freq
(
cmos_rtc
.
rtc
->
irq_freq
);
CMOS_WRITE
(
RTC_REF_CLCK_32KHZ
|
0x06
,
RTC_FREQ_SELECT
);
}
...
...
@@ -780,12 +817,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto
cleanup1
;
}
hpet_rtc_timer_init
();
if
(
use_hpet_alarm
())
hpet_rtc_timer_init
();
if
(
is_valid_irq
(
rtc_irq
))
{
irq_handler_t
rtc_cmos_int_handler
;
if
(
is
_hpet_
enabled
())
{
if
(
use
_hpet_
alarm
())
{
rtc_cmos_int_handler
=
hpet_rtc_interrupt
;
retval
=
hpet_register_irq_handler
(
cmos_interrupt
);
if
(
retval
)
{
...
...
@@ -824,7 +862,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
"alarms up to one day"
,
cmos_rtc
.
century
?
", y3k"
:
""
,
nvmem_cfg
.
size
,
is
_hpet_
enabled
()
?
", hpet irqs"
:
""
);
use
_hpet_
alarm
()
?
", hpet irqs"
:
""
);
return
0
;
...
...
@@ -858,7 +896,8 @@ static void cmos_do_remove(struct device *dev)
if
(
is_valid_irq
(
cmos
->
irq
))
{
free_irq
(
cmos
->
irq
,
cmos
->
rtc
);
hpet_unregister_irq_handler
(
cmos_interrupt
);
if
(
use_hpet_alarm
())
hpet_unregister_irq_handler
(
cmos_interrupt
);
}
cmos
->
rtc
=
NULL
;
...
...
@@ -935,13 +974,13 @@ static int cmos_suspend(struct device *dev)
mask
=
RTC_IRQMASK
;
tmp
&=
~
mask
;
CMOS_WRITE
(
tmp
,
RTC_CONTROL
);
hpet_mask_rtc_irq_bit
(
mask
);
if
(
use_hpet_alarm
())
hpet_mask_rtc_irq_bit
(
mask
);
cmos_checkintr
(
cmos
,
tmp
);
}
spin_unlock_irq
(
&
rtc_lock
);
if
(
tmp
&
RTC_AIE
)
{
if
(
(
tmp
&
RTC_AIE
)
&&
!
use_acpi_alarm
)
{
cmos
->
enabled_wake
=
1
;
if
(
cmos
->
wake_on
)
cmos
->
wake_on
(
dev
);
...
...
@@ -976,8 +1015,26 @@ static void cmos_check_wkalrm(struct device *dev)
{
struct
cmos_rtc
*
cmos
=
dev_get_drvdata
(
dev
);
struct
rtc_wkalrm
current_alarm
;
time64_t
t_now
;
time64_t
t_current_expires
;
time64_t
t_saved_expires
;
struct
rtc_time
now
;
/* Check if we have RTC Alarm armed */
if
(
!
(
cmos
->
suspend_ctrl
&
RTC_AIE
))
return
;
cmos_read_time
(
dev
,
&
now
);
t_now
=
rtc_tm_to_time64
(
&
now
);
/*
* ACPI RTC wake event is cleared after resume from STR,
* ACK the rtc irq here
*/
if
(
t_now
>=
cmos
->
alarm_expires
&&
use_acpi_alarm
)
{
cmos_interrupt
(
0
,
(
void
*
)
cmos
->
rtc
);
return
;
}
cmos_read_alarm
(
dev
,
&
current_alarm
);
t_current_expires
=
rtc_tm_to_time64
(
&
current_alarm
.
time
);
...
...
@@ -996,7 +1053,7 @@ static int __maybe_unused cmos_resume(struct device *dev)
struct
cmos_rtc
*
cmos
=
dev_get_drvdata
(
dev
);
unsigned
char
tmp
;
if
(
cmos
->
enabled_wake
)
{
if
(
cmos
->
enabled_wake
&&
!
use_acpi_alarm
)
{
if
(
cmos
->
wake_off
)
cmos
->
wake_off
(
dev
);
else
...
...
@@ -1014,16 +1071,17 @@ static int __maybe_unused cmos_resume(struct device *dev)
if
(
tmp
&
RTC_IRQMASK
)
{
unsigned
char
mask
;
if
(
device_may_wakeup
(
dev
))
if
(
device_may_wakeup
(
dev
)
&&
use_hpet_alarm
()
)
hpet_rtc_timer_init
();
do
{
CMOS_WRITE
(
tmp
,
RTC_CONTROL
);
hpet_set_rtc_irq_bit
(
tmp
&
RTC_IRQMASK
);
if
(
use_hpet_alarm
())
hpet_set_rtc_irq_bit
(
tmp
&
RTC_IRQMASK
);
mask
=
CMOS_READ
(
RTC_INTR_FLAGS
);
mask
&=
(
tmp
&
RTC_IRQMASK
)
|
RTC_IRQF
;
if
(
!
is
_hpet_
enabled
()
||
!
is_intr
(
mask
))
if
(
!
use
_hpet_
alarm
()
||
!
is_intr
(
mask
))
break
;
/* force one-shot behavior if HPET blocked
...
...
@@ -1068,16 +1126,27 @@ static u32 rtc_handler(void *context)
unsigned
char
rtc_intr
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
rtc_lock
,
flags
);
if
(
cmos_rtc
.
suspend_ctrl
)
rtc_control
=
CMOS_READ
(
RTC_CONTROL
);
if
(
rtc_control
&
RTC_AIE
)
{
cmos_rtc
.
suspend_ctrl
&=
~
RTC_AIE
;
CMOS_WRITE
(
rtc_control
,
RTC_CONTROL
);
rtc_intr
=
CMOS_READ
(
RTC_INTR_FLAGS
);
rtc_update_irq
(
cmos
->
rtc
,
1
,
rtc_intr
);
/*
* Always update rtc irq when ACPI is used as RTC Alarm.
* Or else, ACPI SCI is enabled during suspend/resume only,
* update rtc irq in that case.
*/
if
(
use_acpi_alarm
)
cmos_interrupt
(
0
,
(
void
*
)
cmos
->
rtc
);
else
{
/* Fix me: can we use cmos_interrupt() here as well? */
spin_lock_irqsave
(
&
rtc_lock
,
flags
);
if
(
cmos_rtc
.
suspend_ctrl
)
rtc_control
=
CMOS_READ
(
RTC_CONTROL
);
if
(
rtc_control
&
RTC_AIE
)
{
cmos_rtc
.
suspend_ctrl
&=
~
RTC_AIE
;
CMOS_WRITE
(
rtc_control
,
RTC_CONTROL
);
rtc_intr
=
CMOS_READ
(
RTC_INTR_FLAGS
);
rtc_update_irq
(
cmos
->
rtc
,
1
,
rtc_intr
);
}
spin_unlock_irqrestore
(
&
rtc_lock
,
flags
);
}
spin_unlock_irqrestore
(
&
rtc_lock
,
flags
);
pm_wakeup_hard_event
(
dev
);
acpi_clear_event
(
ACPI_EVENT_RTC
);
...
...
@@ -1107,6 +1176,28 @@ static void rtc_wake_off(struct device *dev)
acpi_disable_event
(
ACPI_EVENT_RTC
,
0
);
}
#ifdef CONFIG_X86
/* Enable use_acpi_alarm mode for Intel platforms no earlier than 2015 */
static
void
use_acpi_alarm_quirks
(
void
)
{
int
year
;
if
(
boot_cpu_data
.
x86_vendor
!=
X86_VENDOR_INTEL
)
return
;
if
(
!
(
acpi_gbl_FADT
.
flags
&
ACPI_FADT_LOW_POWER_S0
))
return
;
if
(
!
is_hpet_enabled
())
return
;
if
(
dmi_get_date
(
DMI_BIOS_DATE
,
&
year
,
NULL
,
NULL
)
&&
year
>=
2015
)
use_acpi_alarm
=
true
;
}
#else
static
inline
void
use_acpi_alarm_quirks
(
void
)
{
}
#endif
/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
* its device node and pass extra config data. This helps its driver use
* capabilities that the now-obsolete mc146818 didn't have, and informs it
...
...
@@ -1119,6 +1210,8 @@ static void cmos_wake_setup(struct device *dev)
if
(
acpi_disabled
)
return
;
use_acpi_alarm_quirks
();
rtc_wake_setup
(
dev
);
acpi_rtc_info
.
wake_on
=
rtc_wake_on
;
acpi_rtc_info
.
wake_off
=
rtc_wake_off
;
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment