Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
ff19473b
Commit
ff19473b
authored
Sep 25, 2018
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ib-omap' into devel
parents
c4c958aa
5284521a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
237 additions
and
130 deletions
+237
-130
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm24xx.c
+3
-4
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/pm34xx.c
+5
-9
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-omap.c
+227
-104
include/linux/platform_data/gpio-omap.h
include/linux/platform_data/gpio-omap.h
+2
-13
No files found.
arch/arm/mach-omap2/pm24xx.c
View file @
ff19473b
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
* published by the Free Software Foundation.
* published by the Free Software Foundation.
*/
*/
#include <linux/cpu_pm.h>
#include <linux/suspend.h>
#include <linux/suspend.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
...
@@ -29,8 +30,6 @@
...
@@ -29,8 +30,6 @@
#include <linux/clk-provider.h>
#include <linux/clk-provider.h>
#include <linux/irq.h>
#include <linux/irq.h>
#include <linux/time.h>
#include <linux/time.h>
#include <linux/gpio.h>
#include <linux/platform_data/gpio-omap.h>
#include <asm/fncpy.h>
#include <asm/fncpy.h>
...
@@ -87,7 +86,7 @@ static int omap2_enter_full_retention(void)
...
@@ -87,7 +86,7 @@ static int omap2_enter_full_retention(void)
l
=
omap_ctrl_readl
(
OMAP2_CONTROL_DEVCONF0
)
|
OMAP24XX_USBSTANDBYCTRL
;
l
=
omap_ctrl_readl
(
OMAP2_CONTROL_DEVCONF0
)
|
OMAP24XX_USBSTANDBYCTRL
;
omap_ctrl_writel
(
l
,
OMAP2_CONTROL_DEVCONF0
);
omap_ctrl_writel
(
l
,
OMAP2_CONTROL_DEVCONF0
);
omap2_gpio_prepare_for_idle
(
0
);
cpu_cluster_pm_enter
(
);
/* One last check for pending IRQs to avoid extra latency due
/* One last check for pending IRQs to avoid extra latency due
* to sleeping unnecessarily. */
* to sleeping unnecessarily. */
...
@@ -100,7 +99,7 @@ static int omap2_enter_full_retention(void)
...
@@ -100,7 +99,7 @@ static int omap2_enter_full_retention(void)
OMAP_SDRC_REGADDR
(
SDRC_POWER
));
OMAP_SDRC_REGADDR
(
SDRC_POWER
));
no_sleep:
no_sleep:
omap2_gpio_resume_after_idle
();
cpu_cluster_pm_exit
();
clk_enable
(
osc_ck
);
clk_enable
(
osc_ck
);
...
...
arch/arm/mach-omap2/pm34xx.c
View file @
ff19473b
...
@@ -18,19 +18,18 @@
...
@@ -18,19 +18,18 @@
* published by the Free Software Foundation.
* published by the Free Software Foundation.
*/
*/
#include <linux/cpu_pm.h>
#include <linux/pm.h>
#include <linux/pm.h>
#include <linux/suspend.h>
#include <linux/suspend.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/list.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/omap-dma.h>
#include <linux/omap-dma.h>
#include <linux/omap-gpmc.h>
#include <linux/omap-gpmc.h>
#include <linux/platform_data/gpio-omap.h>
#include <trace/events/power.h>
#include <trace/events/power.h>
...
@@ -197,7 +196,6 @@ void omap_sram_idle(void)
...
@@ -197,7 +196,6 @@ void omap_sram_idle(void)
int
mpu_next_state
=
PWRDM_POWER_ON
;
int
mpu_next_state
=
PWRDM_POWER_ON
;
int
per_next_state
=
PWRDM_POWER_ON
;
int
per_next_state
=
PWRDM_POWER_ON
;
int
core_next_state
=
PWRDM_POWER_ON
;
int
core_next_state
=
PWRDM_POWER_ON
;
int
per_going_off
;
u32
sdrc_pwr
=
0
;
u32
sdrc_pwr
=
0
;
mpu_next_state
=
pwrdm_read_next_pwrst
(
mpu_pwrdm
);
mpu_next_state
=
pwrdm_read_next_pwrst
(
mpu_pwrdm
);
...
@@ -227,10 +225,8 @@ void omap_sram_idle(void)
...
@@ -227,10 +225,8 @@ void omap_sram_idle(void)
pwrdm_pre_transition
(
NULL
);
pwrdm_pre_transition
(
NULL
);
/* PER */
/* PER */
if
(
per_next_state
<
PWRDM_POWER_ON
)
{
if
(
per_next_state
==
PWRDM_POWER_OFF
)
per_going_off
=
(
per_next_state
==
PWRDM_POWER_OFF
)
?
1
:
0
;
cpu_cluster_pm_enter
();
omap2_gpio_prepare_for_idle
(
per_going_off
);
}
/* CORE */
/* CORE */
if
(
core_next_state
<
PWRDM_POWER_ON
)
{
if
(
core_next_state
<
PWRDM_POWER_ON
)
{
...
@@ -295,8 +291,8 @@ void omap_sram_idle(void)
...
@@ -295,8 +291,8 @@ void omap_sram_idle(void)
pwrdm_post_transition
(
NULL
);
pwrdm_post_transition
(
NULL
);
/* PER */
/* PER */
if
(
per_next_state
<
PWRDM_POWER_ON
)
if
(
per_next_state
==
PWRDM_POWER_OFF
)
omap2_gpio_resume_after_idle
();
cpu_cluster_pm_exit
();
}
}
static
void
omap3_pm_idle
(
void
)
static
void
omap3_pm_idle
(
void
)
...
...
drivers/gpio/gpio-omap.c
View file @
ff19473b
...
@@ -19,6 +19,7 @@
...
@@ -19,6 +19,7 @@
#include <linux/err.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/cpu_pm.h>
#include <linux/device.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/pm_runtime.h>
#include <linux/pm.h>
#include <linux/pm.h>
...
@@ -28,9 +29,11 @@
...
@@ -28,9 +29,11 @@
#include <linux/bitops.h>
#include <linux/bitops.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/gpio-omap.h>
#define OFF_MODE 1
#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
#define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER BIT(2)
#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN BIT(1)
static
LIST_HEAD
(
omap_gpio_list
);
static
LIST_HEAD
(
omap_gpio_list
);
struct
gpio_regs
{
struct
gpio_regs
{
...
@@ -48,6 +51,13 @@ struct gpio_regs {
...
@@ -48,6 +51,13 @@ struct gpio_regs {
u32
debounce_en
;
u32
debounce_en
;
};
};
struct
gpio_bank
;
struct
gpio_omap_funcs
{
void
(
*
idle_enable_level_quirk
)(
struct
gpio_bank
*
bank
);
void
(
*
idle_disable_level_quirk
)(
struct
gpio_bank
*
bank
);
};
struct
gpio_bank
{
struct
gpio_bank
{
struct
list_head
node
;
struct
list_head
node
;
void
__iomem
*
base
;
void
__iomem
*
base
;
...
@@ -55,6 +65,7 @@ struct gpio_bank {
...
@@ -55,6 +65,7 @@ struct gpio_bank {
u32
non_wakeup_gpios
;
u32
non_wakeup_gpios
;
u32
enabled_non_wakeup_gpios
;
u32
enabled_non_wakeup_gpios
;
struct
gpio_regs
context
;
struct
gpio_regs
context
;
struct
gpio_omap_funcs
funcs
;
u32
saved_datain
;
u32
saved_datain
;
u32
level_mask
;
u32
level_mask
;
u32
toggle_mask
;
u32
toggle_mask
;
...
@@ -62,6 +73,8 @@ struct gpio_bank {
...
@@ -62,6 +73,8 @@ struct gpio_bank {
raw_spinlock_t
wa_lock
;
raw_spinlock_t
wa_lock
;
struct
gpio_chip
chip
;
struct
gpio_chip
chip
;
struct
clk
*
dbck
;
struct
clk
*
dbck
;
struct
notifier_block
nb
;
unsigned
int
is_suspended
:
1
;
u32
mod_usage
;
u32
mod_usage
;
u32
irq_usage
;
u32
irq_usage
;
u32
dbck_enable_mask
;
u32
dbck_enable_mask
;
...
@@ -73,8 +86,8 @@ struct gpio_bank {
...
@@ -73,8 +86,8 @@ struct gpio_bank {
int
stride
;
int
stride
;
u32
width
;
u32
width
;
int
context_loss_count
;
int
context_loss_count
;
int
power_mode
;
bool
workaround_enabled
;
bool
workaround_enabled
;
u32
quirks
;
void
(
*
set_dataout
)(
struct
gpio_bank
*
bank
,
unsigned
gpio
,
int
enable
);
void
(
*
set_dataout
)(
struct
gpio_bank
*
bank
,
unsigned
gpio
,
int
enable
);
void
(
*
set_dataout_multiple
)(
struct
gpio_bank
*
bank
,
void
(
*
set_dataout_multiple
)(
struct
gpio_bank
*
bank
,
...
@@ -368,9 +381,18 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
...
@@ -368,9 +381,18 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
readl_relaxed
(
bank
->
base
+
bank
->
regs
->
fallingdetect
);
readl_relaxed
(
bank
->
base
+
bank
->
regs
->
fallingdetect
);
if
(
likely
(
!
(
bank
->
non_wakeup_gpios
&
gpio_bit
)))
{
if
(
likely
(
!
(
bank
->
non_wakeup_gpios
&
gpio_bit
)))
{
omap_gpio_rmw
(
base
,
bank
->
regs
->
wkup_en
,
gpio_bit
,
trigger
!=
0
);
/* Defer wkup_en register update until we idle? */
bank
->
context
.
wake_en
=
if
(
bank
->
quirks
&
OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN
)
{
readl_relaxed
(
bank
->
base
+
bank
->
regs
->
wkup_en
);
if
(
trigger
)
bank
->
context
.
wake_en
|=
gpio_bit
;
else
bank
->
context
.
wake_en
&=
~
gpio_bit
;
}
else
{
omap_gpio_rmw
(
base
,
bank
->
regs
->
wkup_en
,
gpio_bit
,
trigger
!=
0
);
bank
->
context
.
wake_en
=
readl_relaxed
(
bank
->
base
+
bank
->
regs
->
wkup_en
);
}
}
}
/* This part needs to be executed always for OMAP{34xx, 44xx} */
/* This part needs to be executed always for OMAP{34xx, 44xx} */
...
@@ -741,7 +763,9 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
...
@@ -741,7 +763,9 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
if
(
WARN_ON
(
!
isr_reg
))
if
(
WARN_ON
(
!
isr_reg
))
goto
exit
;
goto
exit
;
pm_runtime_get_sync
(
bank
->
chip
.
parent
);
if
(
WARN_ONCE
(
!
pm_runtime_active
(
bank
->
chip
.
parent
),
"gpio irq%i while runtime suspended?
\n
"
,
irq
))
return
IRQ_NONE
;
while
(
1
)
{
while
(
1
)
{
raw_spin_lock_irqsave
(
&
bank
->
lock
,
lock_flags
);
raw_spin_lock_irqsave
(
&
bank
->
lock
,
lock_flags
);
...
@@ -792,7 +816,6 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
...
@@ -792,7 +816,6 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
}
}
}
}
exit:
exit:
pm_runtime_put
(
bank
->
chip
.
parent
);
return
IRQ_HANDLED
;
return
IRQ_HANDLED
;
}
}
...
@@ -899,6 +922,82 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
...
@@ -899,6 +922,82 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
}
}
/*
* Only edges can generate a wakeup event to the PRCM.
*
* Therefore, ensure any wake-up capable GPIOs have
* edge-detection enabled before going idle to ensure a wakeup
* to the PRCM is generated on a GPIO transition. (c.f. 34xx
* NDA TRM 25.5.3.1)
*
* The normal values will be restored upon ->runtime_resume()
* by writing back the values saved in bank->context.
*/
static
void
__maybe_unused
omap2_gpio_enable_level_quirk
(
struct
gpio_bank
*
bank
)
{
u32
wake_low
,
wake_hi
;
/* Enable additional edge detection for level gpios for idle */
wake_low
=
bank
->
context
.
leveldetect0
&
bank
->
context
.
wake_en
;
if
(
wake_low
)
writel_relaxed
(
wake_low
|
bank
->
context
.
fallingdetect
,
bank
->
base
+
bank
->
regs
->
fallingdetect
);
wake_hi
=
bank
->
context
.
leveldetect1
&
bank
->
context
.
wake_en
;
if
(
wake_hi
)
writel_relaxed
(
wake_hi
|
bank
->
context
.
risingdetect
,
bank
->
base
+
bank
->
regs
->
risingdetect
);
}
static
void
__maybe_unused
omap2_gpio_disable_level_quirk
(
struct
gpio_bank
*
bank
)
{
/* Disable edge detection for level gpios after idle */
writel_relaxed
(
bank
->
context
.
fallingdetect
,
bank
->
base
+
bank
->
regs
->
fallingdetect
);
writel_relaxed
(
bank
->
context
.
risingdetect
,
bank
->
base
+
bank
->
regs
->
risingdetect
);
}
/*
* On omap4 and later SoC variants a level interrupt with wkup_en
* enabled blocks the GPIO functional clock from idling until the GPIO
* instance has been reset. To avoid that, we must set wkup_en only for
* idle for level interrupts, and clear level registers for the duration
* of idle. The level interrupts will be still there on wakeup by their
* nature.
*/
static
void
__maybe_unused
omap4_gpio_enable_level_quirk
(
struct
gpio_bank
*
bank
)
{
/* Update wake register for idle, edge bits might be already set */
writel_relaxed
(
bank
->
context
.
wake_en
,
bank
->
base
+
bank
->
regs
->
wkup_en
);
/* Clear level registers for idle */
writel_relaxed
(
0
,
bank
->
base
+
bank
->
regs
->
leveldetect0
);
writel_relaxed
(
0
,
bank
->
base
+
bank
->
regs
->
leveldetect1
);
}
static
void
__maybe_unused
omap4_gpio_disable_level_quirk
(
struct
gpio_bank
*
bank
)
{
/* Restore level registers after idle */
writel_relaxed
(
bank
->
context
.
leveldetect0
,
bank
->
base
+
bank
->
regs
->
leveldetect0
);
writel_relaxed
(
bank
->
context
.
leveldetect1
,
bank
->
base
+
bank
->
regs
->
leveldetect1
);
/* Clear saved wkup_en for level, it will be set for next idle again */
bank
->
context
.
wake_en
&=
~
(
bank
->
context
.
leveldetect0
|
bank
->
context
.
leveldetect1
);
/* Update wake with only edge configuration */
writel_relaxed
(
bank
->
context
.
wake_en
,
bank
->
base
+
bank
->
regs
->
wkup_en
);
}
/*---------------------------------------------------------------------*/
/*---------------------------------------------------------------------*/
static
int
omap_mpuio_suspend_noirq
(
struct
device
*
dev
)
static
int
omap_mpuio_suspend_noirq
(
struct
device
*
dev
)
...
@@ -1218,6 +1317,38 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
...
@@ -1218,6 +1317,38 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
return
ret
;
return
ret
;
}
}
static
void
omap_gpio_idle
(
struct
gpio_bank
*
bank
,
bool
may_lose_context
);
static
void
omap_gpio_unidle
(
struct
gpio_bank
*
bank
);
static
int
gpio_omap_cpu_notifier
(
struct
notifier_block
*
nb
,
unsigned
long
cmd
,
void
*
v
)
{
struct
gpio_bank
*
bank
;
struct
device
*
dev
;
unsigned
long
flags
;
bank
=
container_of
(
nb
,
struct
gpio_bank
,
nb
);
dev
=
bank
->
chip
.
parent
;
raw_spin_lock_irqsave
(
&
bank
->
lock
,
flags
);
switch
(
cmd
)
{
case
CPU_CLUSTER_PM_ENTER
:
if
(
bank
->
is_suspended
)
break
;
omap_gpio_idle
(
bank
,
true
);
break
;
case
CPU_CLUSTER_PM_ENTER_FAILED
:
case
CPU_CLUSTER_PM_EXIT
:
if
(
bank
->
is_suspended
)
break
;
omap_gpio_unidle
(
bank
);
break
;
}
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
return
NOTIFY_OK
;
}
static
const
struct
of_device_id
omap_gpio_match
[];
static
const
struct
of_device_id
omap_gpio_match
[];
static
int
omap_gpio_probe
(
struct
platform_device
*
pdev
)
static
int
omap_gpio_probe
(
struct
platform_device
*
pdev
)
...
@@ -1270,6 +1401,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
...
@@ -1270,6 +1401,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank
->
chip
.
parent
=
dev
;
bank
->
chip
.
parent
=
dev
;
bank
->
chip
.
owner
=
THIS_MODULE
;
bank
->
chip
.
owner
=
THIS_MODULE
;
bank
->
dbck_flag
=
pdata
->
dbck_flag
;
bank
->
dbck_flag
=
pdata
->
dbck_flag
;
bank
->
quirks
=
pdata
->
quirks
;
bank
->
stride
=
pdata
->
bank_stride
;
bank
->
stride
=
pdata
->
bank_stride
;
bank
->
width
=
pdata
->
bank_width
;
bank
->
width
=
pdata
->
bank_width
;
bank
->
is_mpuio
=
pdata
->
is_mpuio
;
bank
->
is_mpuio
=
pdata
->
is_mpuio
;
...
@@ -1278,6 +1410,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
...
@@ -1278,6 +1410,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO
#ifdef CONFIG_OF_GPIO
bank
->
chip
.
of_node
=
of_node_get
(
node
);
bank
->
chip
.
of_node
=
of_node_get
(
node
);
#endif
#endif
if
(
node
)
{
if
(
node
)
{
if
(
!
of_property_read_bool
(
node
,
"ti,gpio-always-on"
))
if
(
!
of_property_read_bool
(
node
,
"ti,gpio-always-on"
))
bank
->
loses_context
=
true
;
bank
->
loses_context
=
true
;
...
@@ -1298,6 +1431,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
...
@@ -1298,6 +1431,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_set_gpio_dataout_mask_multiple
;
omap_set_gpio_dataout_mask_multiple
;
}
}
if
(
bank
->
quirks
&
OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN
)
{
bank
->
funcs
.
idle_enable_level_quirk
=
omap4_gpio_enable_level_quirk
;
bank
->
funcs
.
idle_disable_level_quirk
=
omap4_gpio_disable_level_quirk
;
}
else
if
(
bank
->
quirks
&
OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER
)
{
bank
->
funcs
.
idle_enable_level_quirk
=
omap2_gpio_enable_level_quirk
;
bank
->
funcs
.
idle_disable_level_quirk
=
omap2_gpio_disable_level_quirk
;
}
raw_spin_lock_init
(
&
bank
->
lock
);
raw_spin_lock_init
(
&
bank
->
lock
);
raw_spin_lock_init
(
&
bank
->
wa_lock
);
raw_spin_lock_init
(
&
bank
->
wa_lock
);
...
@@ -1322,7 +1467,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
...
@@ -1322,7 +1467,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
platform_set_drvdata
(
pdev
,
bank
);
platform_set_drvdata
(
pdev
,
bank
);
pm_runtime_enable
(
dev
);
pm_runtime_enable
(
dev
);
pm_runtime_irq_safe
(
dev
);
pm_runtime_get_sync
(
dev
);
pm_runtime_get_sync
(
dev
);
if
(
bank
->
is_mpuio
)
if
(
bank
->
is_mpuio
)
...
@@ -1341,6 +1485,12 @@ static int omap_gpio_probe(struct platform_device *pdev)
...
@@ -1341,6 +1485,12 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_gpio_show_rev
(
bank
);
omap_gpio_show_rev
(
bank
);
if
(
bank
->
funcs
.
idle_enable_level_quirk
&&
bank
->
funcs
.
idle_disable_level_quirk
)
{
bank
->
nb
.
notifier_call
=
gpio_omap_cpu_notifier
;
cpu_pm_register_notifier
(
&
bank
->
nb
);
}
pm_runtime_put
(
dev
);
pm_runtime_put
(
dev
);
list_add_tail
(
&
bank
->
node
,
&
omap_gpio_list
);
list_add_tail
(
&
bank
->
node
,
&
omap_gpio_list
);
...
@@ -1352,6 +1502,8 @@ static int omap_gpio_remove(struct platform_device *pdev)
...
@@ -1352,6 +1502,8 @@ static int omap_gpio_remove(struct platform_device *pdev)
{
{
struct
gpio_bank
*
bank
=
platform_get_drvdata
(
pdev
);
struct
gpio_bank
*
bank
=
platform_get_drvdata
(
pdev
);
if
(
bank
->
nb
.
notifier_call
)
cpu_pm_unregister_notifier
(
&
bank
->
nb
);
list_del
(
&
bank
->
node
);
list_del
(
&
bank
->
node
);
gpiochip_remove
(
&
bank
->
chip
);
gpiochip_remove
(
&
bank
->
chip
);
pm_runtime_disable
(
&
pdev
->
dev
);
pm_runtime_disable
(
&
pdev
->
dev
);
...
@@ -1361,48 +1513,22 @@ static int omap_gpio_remove(struct platform_device *pdev)
...
@@ -1361,48 +1513,22 @@ static int omap_gpio_remove(struct platform_device *pdev)
return
0
;
return
0
;
}
}
#ifdef CONFIG_ARCH_OMAP2PLUS
#if defined(CONFIG_PM)
static
void
omap_gpio_restore_context
(
struct
gpio_bank
*
bank
);
static
void
omap_gpio_restore_context
(
struct
gpio_bank
*
bank
);
static
int
omap_gpio_runtime_suspend
(
struct
device
*
dev
)
static
void
omap_gpio_idle
(
struct
gpio_bank
*
bank
,
bool
may_lose_context
)
{
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
device
*
dev
=
bank
->
chip
.
parent
;
struct
gpio_bank
*
bank
=
platform_get_drvdata
(
pdev
);
u32
l1
=
0
,
l2
=
0
;
u32
l1
=
0
,
l2
=
0
;
unsigned
long
flags
;
u32
wake_low
,
wake_hi
;
raw_spin_lock_irqsave
(
&
bank
->
lock
,
flags
);
/*
if
(
bank
->
funcs
.
idle_enable_level_quirk
)
* Only edges can generate a wakeup event to the PRCM.
bank
->
funcs
.
idle_enable_level_quirk
(
bank
);
*
* Therefore, ensure any wake-up capable GPIOs have
* edge-detection enabled before going idle to ensure a wakeup
* to the PRCM is generated on a GPIO transition. (c.f. 34xx
* NDA TRM 25.5.3.1)
*
* The normal values will be restored upon ->runtime_resume()
* by writing back the values saved in bank->context.
*/
wake_low
=
bank
->
context
.
leveldetect0
&
bank
->
context
.
wake_en
;
if
(
wake_low
)
writel_relaxed
(
wake_low
|
bank
->
context
.
fallingdetect
,
bank
->
base
+
bank
->
regs
->
fallingdetect
);
wake_hi
=
bank
->
context
.
leveldetect1
&
bank
->
context
.
wake_en
;
if
(
wake_hi
)
writel_relaxed
(
wake_hi
|
bank
->
context
.
risingdetect
,
bank
->
base
+
bank
->
regs
->
risingdetect
);
if
(
!
bank
->
enabled_non_wakeup_gpios
)
if
(
!
bank
->
enabled_non_wakeup_gpios
)
goto
update_gpio_context_count
;
goto
update_gpio_context_count
;
if
(
bank
->
power_mode
!=
OFF_MODE
)
{
if
(
!
may_lose_context
)
bank
->
power_mode
=
0
;
goto
update_gpio_context_count
;
goto
update_gpio_context_count
;
}
/*
/*
* If going to OFF, remove triggering for all
* If going to OFF, remove triggering for all
* non-wakeup GPIOs. Otherwise spurious IRQs will be
* non-wakeup GPIOs. Otherwise spurious IRQs will be
...
@@ -1427,23 +1553,16 @@ static int omap_gpio_runtime_suspend(struct device *dev)
...
@@ -1427,23 +1553,16 @@ static int omap_gpio_runtime_suspend(struct device *dev)
bank
->
get_context_loss_count
(
dev
);
bank
->
get_context_loss_count
(
dev
);
omap_gpio_dbck_disable
(
bank
);
omap_gpio_dbck_disable
(
bank
);
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
return
0
;
}
}
static
void
omap_gpio_init_context
(
struct
gpio_bank
*
p
);
static
void
omap_gpio_init_context
(
struct
gpio_bank
*
p
);
static
int
omap_gpio_runtime_resume
(
struct
device
*
dev
)
static
void
omap_gpio_unidle
(
struct
gpio_bank
*
bank
)
{
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
device
*
dev
=
bank
->
chip
.
parent
;
struct
gpio_bank
*
bank
=
platform_get_drvdata
(
pdev
);
u32
l
=
0
,
gen
,
gen0
,
gen1
;
u32
l
=
0
,
gen
,
gen0
,
gen1
;
unsigned
long
flags
;
int
c
;
int
c
;
raw_spin_lock_irqsave
(
&
bank
->
lock
,
flags
);
/*
/*
* On the first resume during the probe, the context has not
* On the first resume during the probe, the context has not
* been initialised and so initialise it now. Also initialise
* been initialised and so initialise it now. Also initialise
...
@@ -1459,16 +1578,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
...
@@ -1459,16 +1578,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
omap_gpio_dbck_enable
(
bank
);
omap_gpio_dbck_enable
(
bank
);
/*
if
(
bank
->
funcs
.
idle_disable_level_quirk
)
* In ->runtime_suspend(), level-triggered, wakeup-enabled
bank
->
funcs
.
idle_disable_level_quirk
(
bank
);
* GPIOs were set to edge trigger also in order to be able to
* generate a PRCM wakeup. Here we restore the
* pre-runtime_suspend() values for edge triggering.
*/
writel_relaxed
(
bank
->
context
.
fallingdetect
,
bank
->
base
+
bank
->
regs
->
fallingdetect
);
writel_relaxed
(
bank
->
context
.
risingdetect
,
bank
->
base
+
bank
->
regs
->
risingdetect
);
if
(
bank
->
loses_context
)
{
if
(
bank
->
loses_context
)
{
if
(
!
bank
->
get_context_loss_count
)
{
if
(
!
bank
->
get_context_loss_count
)
{
...
@@ -1478,16 +1589,13 @@ static int omap_gpio_runtime_resume(struct device *dev)
...
@@ -1478,16 +1589,13 @@ static int omap_gpio_runtime_resume(struct device *dev)
if
(
c
!=
bank
->
context_loss_count
)
{
if
(
c
!=
bank
->
context_loss_count
)
{
omap_gpio_restore_context
(
bank
);
omap_gpio_restore_context
(
bank
);
}
else
{
}
else
{
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
return
;
return
0
;
}
}
}
}
}
}
if
(
!
bank
->
workaround_enabled
)
{
if
(
!
bank
->
workaround_enabled
)
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
return
;
return
0
;
}
l
=
readl_relaxed
(
bank
->
base
+
bank
->
regs
->
datain
);
l
=
readl_relaxed
(
bank
->
base
+
bank
->
regs
->
datain
);
...
@@ -1540,41 +1648,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
...
@@ -1540,41 +1648,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
}
}
bank
->
workaround_enabled
=
false
;
bank
->
workaround_enabled
=
false
;
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
return
0
;
}
#endif
/* CONFIG_PM */
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
void
omap2_gpio_prepare_for_idle
(
int
pwr_mode
)
{
struct
gpio_bank
*
bank
;
list_for_each_entry
(
bank
,
&
omap_gpio_list
,
node
)
{
if
(
!
BANK_USED
(
bank
)
||
!
bank
->
loses_context
)
continue
;
bank
->
power_mode
=
pwr_mode
;
pm_runtime_put_sync_suspend
(
bank
->
chip
.
parent
);
}
}
void
omap2_gpio_resume_after_idle
(
void
)
{
struct
gpio_bank
*
bank
;
list_for_each_entry
(
bank
,
&
omap_gpio_list
,
node
)
{
if
(
!
BANK_USED
(
bank
)
||
!
bank
->
loses_context
)
continue
;
pm_runtime_get_sync
(
bank
->
chip
.
parent
);
}
}
}
#endif
#if defined(CONFIG_PM)
static
void
omap_gpio_init_context
(
struct
gpio_bank
*
p
)
static
void
omap_gpio_init_context
(
struct
gpio_bank
*
p
)
{
{
struct
omap_gpio_reg_offs
*
regs
=
p
->
regs
;
struct
omap_gpio_reg_offs
*
regs
=
p
->
regs
;
...
@@ -1631,17 +1706,57 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
...
@@ -1631,17 +1706,57 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
writel_relaxed
(
bank
->
context
.
irqenable2
,
writel_relaxed
(
bank
->
context
.
irqenable2
,
bank
->
base
+
bank
->
regs
->
irqenable2
);
bank
->
base
+
bank
->
regs
->
irqenable2
);
}
}
#endif
/* CONFIG_PM */
#else
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
static
inline
void
omap_gpio_init_context
(
struct
gpio_bank
*
p
)
{}
#endif
static
int
__maybe_unused
omap_gpio_runtime_suspend
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
gpio_bank
*
bank
=
platform_get_drvdata
(
pdev
);
unsigned
long
flags
;
int
error
=
0
;
raw_spin_lock_irqsave
(
&
bank
->
lock
,
flags
);
/* Must be idled only by CPU_CLUSTER_PM_ENTER? */
if
(
bank
->
irq_usage
)
{
error
=
-
EBUSY
;
goto
unlock
;
}
omap_gpio_idle
(
bank
,
true
);
bank
->
is_suspended
=
true
;
unlock:
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
return
error
;
}
static
int
__maybe_unused
omap_gpio_runtime_resume
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
gpio_bank
*
bank
=
platform_get_drvdata
(
pdev
);
unsigned
long
flags
;
int
error
=
0
;
raw_spin_lock_irqsave
(
&
bank
->
lock
,
flags
);
/* Must be unidled only by CPU_CLUSTER_PM_ENTER? */
if
(
bank
->
irq_usage
)
{
error
=
-
EBUSY
;
goto
unlock
;
}
omap_gpio_unidle
(
bank
);
bank
->
is_suspended
=
false
;
unlock:
raw_spin_unlock_irqrestore
(
&
bank
->
lock
,
flags
);
return
error
;
}
#ifdef CONFIG_ARCH_OMAP2PLUS
static
const
struct
dev_pm_ops
gpio_pm_ops
=
{
static
const
struct
dev_pm_ops
gpio_pm_ops
=
{
SET_RUNTIME_PM_OPS
(
omap_gpio_runtime_suspend
,
omap_gpio_runtime_resume
,
SET_RUNTIME_PM_OPS
(
omap_gpio_runtime_suspend
,
omap_gpio_runtime_resume
,
NULL
)
NULL
)
};
};
#else
static
const
struct
dev_pm_ops
gpio_pm_ops
;
#endif
/* CONFIG_ARCH_OMAP2PLUS */
#if defined(CONFIG_OF)
#if defined(CONFIG_OF)
static
struct
omap_gpio_reg_offs
omap2_gpio_regs
=
{
static
struct
omap_gpio_reg_offs
omap2_gpio_regs
=
{
...
@@ -1690,6 +1805,11 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
...
@@ -1690,6 +1805,11 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.
fallingdetect
=
OMAP4_GPIO_FALLINGDETECT
,
.
fallingdetect
=
OMAP4_GPIO_FALLINGDETECT
,
};
};
/*
* Note that omap2 does not currently support idle modes with context loss so
* no need to add OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER quirk flag to save
* and restore context.
*/
static
const
struct
omap_gpio_platform_data
omap2_pdata
=
{
static
const
struct
omap_gpio_platform_data
omap2_pdata
=
{
.
regs
=
&
omap2_gpio_regs
,
.
regs
=
&
omap2_gpio_regs
,
.
bank_width
=
32
,
.
bank_width
=
32
,
...
@@ -1700,12 +1820,15 @@ static const struct omap_gpio_platform_data omap3_pdata = {
...
@@ -1700,12 +1820,15 @@ static const struct omap_gpio_platform_data omap3_pdata = {
.
regs
=
&
omap2_gpio_regs
,
.
regs
=
&
omap2_gpio_regs
,
.
bank_width
=
32
,
.
bank_width
=
32
,
.
dbck_flag
=
true
,
.
dbck_flag
=
true
,
.
quirks
=
OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER
,
};
};
static
const
struct
omap_gpio_platform_data
omap4_pdata
=
{
static
const
struct
omap_gpio_platform_data
omap4_pdata
=
{
.
regs
=
&
omap4_gpio_regs
,
.
regs
=
&
omap4_gpio_regs
,
.
bank_width
=
32
,
.
bank_width
=
32
,
.
dbck_flag
=
true
,
.
dbck_flag
=
true
,
.
quirks
=
OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER
|
OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN
,
};
};
static
const
struct
of_device_id
omap_gpio_match
[]
=
{
static
const
struct
of_device_id
omap_gpio_match
[]
=
{
...
...
include/linux/platform_data/gpio-omap.h
View file @
ff19473b
...
@@ -197,23 +197,12 @@ struct omap_gpio_platform_data {
...
@@ -197,23 +197,12 @@ struct omap_gpio_platform_data {
bool
is_mpuio
;
/* whether the bank is of type MPUIO */
bool
is_mpuio
;
/* whether the bank is of type MPUIO */
u32
non_wakeup_gpios
;
u32
non_wakeup_gpios
;
u32
quirks
;
/* Version specific quirks mask */
struct
omap_gpio_reg_offs
*
regs
;
struct
omap_gpio_reg_offs
*
regs
;
/* Return context loss count due to PM states changing */
/* Return context loss count due to PM states changing */
int
(
*
get_context_loss_count
)(
struct
device
*
dev
);
int
(
*
get_context_loss_count
)(
struct
device
*
dev
);
};
};
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
extern
void
omap2_gpio_prepare_for_idle
(
int
off_mode
);
extern
void
omap2_gpio_resume_after_idle
(
void
);
#else
static
inline
void
omap2_gpio_prepare_for_idle
(
int
off_mode
)
{
}
static
inline
void
omap2_gpio_resume_after_idle
(
void
)
{
}
#endif
#endif
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment