You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'omap-for-v4.2/wakeirq-drivers-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/late
Merge "omap generic wakeirq for v4.2 merge window" from Tony Lindgren: Omap driver changes for v4.2 to switch drivers over to Linux generic wake IRQ events for omap_hsmmc, 8250_omap and omap-serial drivers. The generic wake IRQs also fix issues that these drivers potentially have with IRQ re-entrancy at least for serial-omap. Note that because of dependencies and merge conflicts these are based on Rafael's pm-wakeirq and Greg's tty-next branches. * tag 'omap-for-v4.2/wakeirq-drivers-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (148 commits) serial: 8250_omap: Move wake-up interrupt to generic wakeirq serial: omap: Switch wake-up interrupt to generic wakeirq tty: move linux/gsmmux.h to uapi doc: dt: add documentation for nxp,lpc1850-uart serial: 8250: add LPC18xx/43xx UART driver serial: 8250_uniphier: add UniPhier serial driver serial: 8250_dw: support ACPI platforms with integrated DMA engine serial: of_serial: check the return value of clk_prepare_enable() serial: of_serial: use devm_clk_get() instead of clk_get() serial: earlycon: Add support for big-endian MMIO accesses serial: sirf: use hrtimer for data rx serial: sirf: correct the fifo empty_bit serial: sirf: fix system hung on console log output serial: 8250: remove return statements from void function sc16is7xx: use kworker for RS-485 configuration sc16is7xx: use kworker to update ier bits sc16is7xx: use kworker for md_proc sc16is7xx: move RTS delay to workqueue sc16is7xx: use kthread_worker for tx_work and irq sc16is7xx: use LSR_TEMT_BIT in .tx_empty() ...
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
* ARM SBSA defined generic UART
|
||||
This UART uses a subset of the PL011 registers and consequently lives
|
||||
in the PL011 driver. It's baudrate and other communication parameters
|
||||
cannot be adjusted at runtime, so it lacks a clock specifier here.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "arm,sbsa-uart"
|
||||
- reg: exactly one register range
|
||||
- interrupts: exactly one interrupt specifier
|
||||
- current-speed: the (fixed) baud rate set by the firmware
|
||||
@@ -14,7 +14,14 @@ Required properties:
|
||||
|
||||
- interrupts: A single interrupt specifier.
|
||||
|
||||
- clocks: Clock driving the hardware.
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names:
|
||||
- "baud": The clock the baudrate is derived from
|
||||
- "bus": The bus clock for register accesses (optional)
|
||||
|
||||
For compatibility with older device trees an unnamed clock is used for the
|
||||
baud clock if the baudclk does not exist. Do not use this for new designs.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -22,5 +29,6 @@ Example:
|
||||
compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
|
||||
reg = <0x11006000 0x400>;
|
||||
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&uart_clk>;
|
||||
clocks = <&uart_clk>, <&bus_clk>;
|
||||
clock-names = "baud", "bus";
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
* NXP LPC1850 UART
|
||||
|
||||
Required properties:
|
||||
- compatible : "nxp,lpc1850-uart", "ns16550a".
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : should contain uart interrupt.
|
||||
- clocks : phandle to the input clocks.
|
||||
- clock-names : required elements: "uartclk", "reg".
|
||||
|
||||
Optional properties:
|
||||
- dmas : Two or more DMA channel specifiers following the
|
||||
convention outlined in bindings/dma/dma.txt
|
||||
- dma-names : Names for the dma channels, if present. There must
|
||||
be at least one channel named "tx" for transmit
|
||||
and named "rx" for receive.
|
||||
|
||||
Since it's also possible to also use the of_serial.c driver all
|
||||
parameters from 8250.txt also apply but are optional.
|
||||
|
||||
Example:
|
||||
uart0: serial@40081000 {
|
||||
compatible = "nxp,lpc1850-uart", "ns16550a";
|
||||
reg = <0x40081000 0x1000>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <24>;
|
||||
clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>;
|
||||
clock-names = "uartclk", "reg";
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
* NXP SC16IS7xx advanced Universal Asynchronous Receiver-Transmitter (UART)
|
||||
* i2c as bus
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
@@ -31,3 +32,39 @@ Example:
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
* spi as bus
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
- "nxp,sc16is740" for NXP SC16IS740,
|
||||
- "nxp,sc16is741" for NXP SC16IS741,
|
||||
- "nxp,sc16is750" for NXP SC16IS750,
|
||||
- "nxp,sc16is752" for NXP SC16IS752,
|
||||
- "nxp,sc16is760" for NXP SC16IS760,
|
||||
- "nxp,sc16is762" for NXP SC16IS762.
|
||||
- reg: SPI chip select number.
|
||||
- interrupt-parent: The phandle for the interrupt controller that
|
||||
services interrupts for this IC.
|
||||
- interrupts: Specifies the interrupt source of the parent interrupt
|
||||
controller. The format of the interrupt specifier depends on the
|
||||
parent interrupt controller.
|
||||
- clocks: phandle to the IC source clock.
|
||||
|
||||
Optional properties:
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be two. The first cell is the GPIO number and
|
||||
the second cell is used to specify the GPIO polarity:
|
||||
0 = active high,
|
||||
1 = active low.
|
||||
|
||||
Example:
|
||||
sc16is750: sc16is750@0 {
|
||||
compatible = "nxp,sc16is750";
|
||||
reg = <0>;
|
||||
clocks = <&clk20m>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
@@ -44,6 +44,11 @@ Required properties:
|
||||
Note: Each enabled SCIx UART should have an alias correctly numbered in the
|
||||
"aliases" node.
|
||||
|
||||
Optional properties:
|
||||
- dmas: Must contain a list of two references to DMA specifiers, one for
|
||||
transmission, and one for reception.
|
||||
- dma-names: Must contain a list of two DMA names, "tx" and "rx".
|
||||
|
||||
Example:
|
||||
aliases {
|
||||
serial0 = &scifa0;
|
||||
@@ -56,4 +61,6 @@ Example:
|
||||
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>;
|
||||
clock-names = "sci_ick";
|
||||
dmas = <&dmac0 0x21>, <&dmac0 0x22>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
|
||||
"sirf,atlas7-uart" or "sirf,atlas7-bt-uart" which means
|
||||
uart located in BT module and used for BT.
|
||||
"sirf,atlas7-uart" or "sirf,atlas7-usp-uart".
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- fifosize : Should define hardware rx/tx fifo size
|
||||
@@ -33,15 +32,3 @@ usp@b0090000 {
|
||||
rts-gpios = <&gpio 15 0>;
|
||||
cts-gpios = <&gpio 46 0>;
|
||||
};
|
||||
|
||||
for uart use in BT module,
|
||||
uart6: uart@11000000 {
|
||||
cell-index = <6>;
|
||||
compatible = "sirf,atlas7-bt-uart", "sirf,atlas7-uart";
|
||||
reg = <0x11000000 0x1000>;
|
||||
interrupts = <0 100 0>;
|
||||
clocks = <&clks 138>, <&clks 140>, <&clks 141>;
|
||||
clock-names = "uart", "general", "noc";
|
||||
fifosize = <128>;
|
||||
status = "disabled";
|
||||
}
|
||||
|
||||
@@ -959,14 +959,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
uart[8250],io,<addr>[,options]
|
||||
uart[8250],mmio,<addr>[,options]
|
||||
uart[8250],mmio32,<addr>[,options]
|
||||
uart[8250],mmio32be,<addr>[,options]
|
||||
uart[8250],0x<addr>[,options]
|
||||
Start an early, polled-mode console on the 8250/16550
|
||||
UART at the specified I/O port or MMIO address.
|
||||
MMIO inter-register address stride is either 8-bit
|
||||
(mmio) or 32-bit (mmio32).
|
||||
If none of [io|mmio|mmio32], <addr> is assumed to be
|
||||
equivalent to 'mmio'. 'options' are specified in the
|
||||
same format described for "console=ttyS<n>"; if
|
||||
(mmio) or 32-bit (mmio32 or mmio32be).
|
||||
If none of [io|mmio|mmio32|mmio32be], <addr> is assumed
|
||||
to be equivalent to 'mmio'. 'options' are specified
|
||||
in the same format described for "console=ttyS<n>"; if
|
||||
unspecified, the h/w is not initialized.
|
||||
|
||||
pl011,<addr>
|
||||
|
||||
@@ -556,6 +556,12 @@ helper functions described in Section 4. In that case, pm_runtime_resume()
|
||||
should be used. Of course, for this purpose the device's runtime PM has to be
|
||||
enabled earlier by calling pm_runtime_enable().
|
||||
|
||||
Note, if the device may execute pm_runtime calls during the probe (such as
|
||||
if it is registers with a subsystem that may call back in) then the
|
||||
pm_runtime_get_sync() call paired with a pm_runtime_put() call will be
|
||||
appropriate to ensure that the device is not put back to sleep during the
|
||||
probe. This can happen with systems such as the network device layer.
|
||||
|
||||
It may be desirable to suspend the device once ->probe() has finished.
|
||||
Therefore the driver core uses the asyncronous pm_request_idle() to submit a
|
||||
request to execute the subsystem-level idle callback for the device at that
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define BASE_BAUD ( 1843200 / 16 )
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#else
|
||||
|
||||
@@ -1350,6 +1350,9 @@ void edma_stop(unsigned channel)
|
||||
edma_shadow0_write_array(ctlr, SH_SECR, j, mask);
|
||||
edma_write_array(ctlr, EDMA_EMCR, j, mask);
|
||||
|
||||
/* clear possibly pending completion interrupt */
|
||||
edma_shadow0_write_array(ctlr, SH_ICR, j, mask);
|
||||
|
||||
pr_debug("EDMA: EER%d %08x\n", j,
|
||||
edma_shadow0_read_array(ctlr, SH_EER, j));
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
defined(CONFIG_BFIN_UART2_CTSRTS) || \
|
||||
defined(CONFIG_BFIN_UART3_CTSRTS)
|
||||
# if defined(BFIN_UART_BF54X_STYLE) || defined(BFIN_UART_BF60X_STYLE)
|
||||
# define CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
# define SERIAL_BFIN_HARD_CTSRTS
|
||||
# else
|
||||
# define CONFIG_SERIAL_BFIN_CTSRTS
|
||||
# define SERIAL_BFIN_CTSRTS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -50,8 +50,8 @@ struct bfin_serial_port {
|
||||
#elif ANOMALY_05000363
|
||||
unsigned int anomaly_threshold;
|
||||
#endif
|
||||
#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
|
||||
defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
|
||||
#if defined(SERIAL_BFIN_CTSRTS) || \
|
||||
defined(SERIAL_BFIN_HARD_CTSRTS)
|
||||
int cts_pin;
|
||||
int rts_pin;
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#define BASE_BAUD ( 1843200 / 16 )
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#else
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define _ASM_SERIAL_H
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#else
|
||||
@@ -21,7 +21,7 @@
|
||||
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_MANY_PORTS
|
||||
#ifdef CONFIG_SERIAL_8250_MANY_PORTS
|
||||
#define FOURPORT_FLAGS ASYNC_FOURPORT
|
||||
#define ACCENT_FLAGS 0
|
||||
#define BOCA_FLAGS 0
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#define BASE_BAUD (1843200/16)
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
# define STD_COMX_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
|
||||
# define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | 0 | UPF_AUTO_IRQ)
|
||||
#else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
|
||||
obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o
|
||||
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
|
||||
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
|
||||
obj-$(CONFIG_PM_OPP) += opp.o
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm-trace.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/async.h>
|
||||
@@ -587,6 +588,7 @@ void dpm_resume_noirq(pm_message_t state)
|
||||
async_synchronize_full();
|
||||
dpm_show_time(starttime, state, "noirq");
|
||||
resume_device_irqs();
|
||||
device_wakeup_disarm_wake_irqs();
|
||||
cpuidle_resume();
|
||||
trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
|
||||
}
|
||||
@@ -1104,6 +1106,7 @@ int dpm_suspend_noirq(pm_message_t state)
|
||||
|
||||
trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
|
||||
cpuidle_pause();
|
||||
device_wakeup_arm_wake_irqs();
|
||||
suspend_device_irqs();
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
pm_transition = state;
|
||||
|
||||
@@ -20,6 +20,46 @@ static inline void pm_runtime_early_init(struct device *dev)
|
||||
extern void pm_runtime_init(struct device *dev);
|
||||
extern void pm_runtime_remove(struct device *dev);
|
||||
|
||||
struct wake_irq {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
bool dedicated_irq:1;
|
||||
};
|
||||
|
||||
extern void dev_pm_arm_wake_irq(struct wake_irq *wirq);
|
||||
extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
extern int device_wakeup_attach_irq(struct device *dev,
|
||||
struct wake_irq *wakeirq);
|
||||
extern void device_wakeup_detach_irq(struct device *dev);
|
||||
extern void device_wakeup_arm_wake_irqs(void);
|
||||
extern void device_wakeup_disarm_wake_irqs(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
device_wakeup_attach_irq(struct device *dev,
|
||||
struct wake_irq *wakeirq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void device_wakeup_detach_irq(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void device_wakeup_arm_wake_irqs(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void device_wakeup_disarm_wake_irqs(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/*
|
||||
* sysfs.c
|
||||
*/
|
||||
@@ -52,6 +92,14 @@ static inline void wakeup_sysfs_remove(struct device *dev) {}
|
||||
static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
|
||||
static inline void pm_qos_sysfs_remove(struct device *dev) {}
|
||||
|
||||
static inline void dev_pm_arm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <trace/events/rpm.h>
|
||||
#include "power.h"
|
||||
|
||||
@@ -514,6 +515,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
|
||||
|
||||
callback = RPM_GET_CALLBACK(dev, runtime_suspend);
|
||||
|
||||
dev_pm_enable_wake_irq(dev);
|
||||
retval = rpm_callback(callback, dev);
|
||||
if (retval)
|
||||
goto fail;
|
||||
@@ -552,6 +554,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
|
||||
return retval;
|
||||
|
||||
fail:
|
||||
dev_pm_disable_wake_irq(dev);
|
||||
__update_runtime_status(dev, RPM_ACTIVE);
|
||||
dev->power.deferred_resume = false;
|
||||
wake_up_all(&dev->power.wait_queue);
|
||||
@@ -734,13 +737,16 @@ static int rpm_resume(struct device *dev, int rpmflags)
|
||||
|
||||
callback = RPM_GET_CALLBACK(dev, runtime_resume);
|
||||
|
||||
dev_pm_disable_wake_irq(dev);
|
||||
retval = rpm_callback(callback, dev);
|
||||
if (retval) {
|
||||
__update_runtime_status(dev, RPM_SUSPENDED);
|
||||
pm_runtime_cancel_pending(dev);
|
||||
dev_pm_enable_wake_irq(dev);
|
||||
} else {
|
||||
no_callback:
|
||||
__update_runtime_status(dev, RPM_ACTIVE);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
if (parent)
|
||||
atomic_inc(&parent->power.child_count);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* wakeirq.c - Device wakeirq helper functions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
|
||||
#include "power.h"
|
||||
|
||||
/**
|
||||
* dev_pm_attach_wake_irq - Attach device interrupt as a wake IRQ
|
||||
* @dev: Device entry
|
||||
* @irq: Device wake-up capable interrupt
|
||||
* @wirq: Wake irq specific data
|
||||
*
|
||||
* Internal function to attach either a device IO interrupt or a
|
||||
* dedicated wake-up interrupt as a wake IRQ.
|
||||
*/
|
||||
static int dev_pm_attach_wake_irq(struct device *dev, int irq,
|
||||
struct wake_irq *wirq)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (!dev || !wirq)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev->power.lock, flags);
|
||||
if (dev_WARN_ONCE(dev, dev->power.wakeirq,
|
||||
"wake irq already initialized\n")) {
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
dev->power.wakeirq = wirq;
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
|
||||
err = device_wakeup_attach_irq(dev, wirq);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_set_wake_irq - Attach device IO interrupt as wake IRQ
|
||||
* @dev: Device entry
|
||||
* @irq: Device IO interrupt
|
||||
*
|
||||
* Attach a device IO interrupt as a wake IRQ. The wake IRQ gets
|
||||
* automatically configured for wake-up from suspend based
|
||||
* on the device specific sysfs wakeup entry. Typically called
|
||||
* during driver probe after calling device_init_wakeup().
|
||||
*/
|
||||
int dev_pm_set_wake_irq(struct device *dev, int irq)
|
||||
{
|
||||
struct wake_irq *wirq;
|
||||
int err;
|
||||
|
||||
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
|
||||
if (!wirq)
|
||||
return -ENOMEM;
|
||||
|
||||
wirq->dev = dev;
|
||||
wirq->irq = irq;
|
||||
|
||||
err = dev_pm_attach_wake_irq(dev, irq, wirq);
|
||||
if (err)
|
||||
kfree(wirq);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_clear_wake_irq - Detach a device IO interrupt wake IRQ
|
||||
* @dev: Device entry
|
||||
*
|
||||
* Detach a device wake IRQ and free resources.
|
||||
*
|
||||
* Note that it's OK for drivers to call this without calling
|
||||
* dev_pm_set_wake_irq() as all the driver instances may not have
|
||||
* a wake IRQ configured. This avoid adding wake IRQ specific
|
||||
* checks into the drivers.
|
||||
*/
|
||||
void dev_pm_clear_wake_irq(struct device *dev)
|
||||
{
|
||||
struct wake_irq *wirq = dev->power.wakeirq;
|
||||
unsigned long flags;
|
||||
|
||||
if (!wirq)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->power.lock, flags);
|
||||
dev->power.wakeirq = NULL;
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
|
||||
device_wakeup_detach_irq(dev);
|
||||
if (wirq->dedicated_irq)
|
||||
free_irq(wirq->irq, wirq);
|
||||
kfree(wirq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
|
||||
|
||||
/**
|
||||
* handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
|
||||
* @irq: Device specific dedicated wake-up interrupt
|
||||
* @_wirq: Wake IRQ data
|
||||
*
|
||||
* Some devices have a separate wake-up interrupt in addition to the
|
||||
* device IO interrupt. The wake-up interrupt signals that a device
|
||||
* should be woken up from it's idle state. This handler uses device
|
||||
* specific pm_runtime functions to wake the device, and then it's
|
||||
* up to the device to do whatever it needs to. Note that as the
|
||||
* device may need to restore context and start up regulators, we
|
||||
* use a threaded IRQ.
|
||||
*
|
||||
* Also note that we are not resending the lost device interrupts.
|
||||
* We assume that the wake-up interrupt just needs to wake-up the
|
||||
* device, and then device's pm_runtime_resume() can deal with the
|
||||
* situation.
|
||||
*/
|
||||
static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
|
||||
{
|
||||
struct wake_irq *wirq = _wirq;
|
||||
int res;
|
||||
|
||||
/* We don't want RPM_ASYNC or RPM_NOWAIT here */
|
||||
res = pm_runtime_resume(wirq->dev);
|
||||
if (res < 0)
|
||||
dev_warn(wirq->dev,
|
||||
"wake IRQ with no resume: %i\n", res);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
|
||||
* @dev: Device entry
|
||||
* @irq: Device wake-up interrupt
|
||||
*
|
||||
* Unless your hardware has separate wake-up interrupts in addition
|
||||
* to the device IO interrupts, you don't need this.
|
||||
*
|
||||
* Sets up a threaded interrupt handler for a device that has
|
||||
* a dedicated wake-up interrupt in addition to the device IO
|
||||
* interrupt.
|
||||
*
|
||||
* The interrupt starts disabled, and needs to be managed for
|
||||
* the device by the bus code or the device driver using
|
||||
* dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
|
||||
* functions.
|
||||
*/
|
||||
int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
|
||||
{
|
||||
struct wake_irq *wirq;
|
||||
int err;
|
||||
|
||||
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
|
||||
if (!wirq)
|
||||
return -ENOMEM;
|
||||
|
||||
wirq->dev = dev;
|
||||
wirq->irq = irq;
|
||||
wirq->dedicated_irq = true;
|
||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
|
||||
/*
|
||||
* Consumer device may need to power up and restore state
|
||||
* so we use a threaded irq.
|
||||
*/
|
||||
err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
|
||||
IRQF_ONESHOT, dev_name(dev), wirq);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
err = dev_pm_attach_wake_irq(dev, irq, wirq);
|
||||
if (err)
|
||||
goto err_free_irq;
|
||||
|
||||
return err;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(irq, wirq);
|
||||
err_free:
|
||||
kfree(wirq);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_enable_wake_irq - Enable device wake-up interrupt
|
||||
* @dev: Device
|
||||
*
|
||||
* Called from the bus code or the device driver for
|
||||
* runtime_suspend() to enable the wake-up interrupt while
|
||||
* the device is running.
|
||||
*
|
||||
* Note that for runtime_suspend()) the wake-up interrupts
|
||||
* should be unconditionally enabled unlike for suspend()
|
||||
* that is conditional.
|
||||
*/
|
||||
void dev_pm_enable_wake_irq(struct device *dev)
|
||||
{
|
||||
struct wake_irq *wirq = dev->power.wakeirq;
|
||||
|
||||
if (wirq && wirq->dedicated_irq)
|
||||
enable_irq(wirq->irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_disable_wake_irq - Disable device wake-up interrupt
|
||||
* @dev: Device
|
||||
*
|
||||
* Called from the bus code or the device driver for
|
||||
* runtime_resume() to disable the wake-up interrupt while
|
||||
* the device is running.
|
||||
*/
|
||||
void dev_pm_disable_wake_irq(struct device *dev)
|
||||
{
|
||||
struct wake_irq *wirq = dev->power.wakeirq;
|
||||
|
||||
if (wirq && wirq->dedicated_irq)
|
||||
disable_irq_nosync(wirq->irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_arm_wake_irq - Arm device wake-up
|
||||
* @wirq: Device wake-up interrupt
|
||||
*
|
||||
* Sets up the wake-up event conditionally based on the
|
||||
* device_may_wake().
|
||||
*/
|
||||
void dev_pm_arm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
if (!wirq)
|
||||
return;
|
||||
|
||||
if (device_may_wakeup(wirq->dev))
|
||||
enable_irq_wake(wirq->irq);
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_disarm_wake_irq - Disarm device wake-up
|
||||
* @wirq: Device wake-up interrupt
|
||||
*
|
||||
* Clears up the wake-up event conditionally based on the
|
||||
* device_may_wake().
|
||||
*/
|
||||
void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
if (!wirq)
|
||||
return;
|
||||
|
||||
if (device_may_wakeup(wirq->dev))
|
||||
disable_irq_wake(wirq->irq);
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include "power.h"
|
||||
@@ -238,6 +239,97 @@ int device_wakeup_enable(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_wakeup_enable);
|
||||
|
||||
/**
|
||||
* device_wakeup_attach_irq - Attach a wakeirq to a wakeup source
|
||||
* @dev: Device to handle
|
||||
* @wakeirq: Device specific wakeirq entry
|
||||
*
|
||||
* Attach a device wakeirq to the wakeup source so the device
|
||||
* wake IRQ can be configured automatically for suspend and
|
||||
* resume.
|
||||
*/
|
||||
int device_wakeup_attach_irq(struct device *dev,
|
||||
struct wake_irq *wakeirq)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
ws = dev->power.wakeup;
|
||||
if (!ws) {
|
||||
dev_err(dev, "forgot to call call device_init_wakeup?\n");
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (ws->wakeirq) {
|
||||
ret = -EEXIST;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ws->wakeirq = wakeirq;
|
||||
|
||||
unlock:
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_detach_irq - Detach a wakeirq from a wakeup source
|
||||
* @dev: Device to handle
|
||||
*
|
||||
* Removes a device wakeirq from the wakeup source.
|
||||
*/
|
||||
void device_wakeup_detach_irq(struct device *dev)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
ws = dev->power.wakeup;
|
||||
if (!ws)
|
||||
goto unlock;
|
||||
|
||||
ws->wakeirq = NULL;
|
||||
|
||||
unlock:
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_arm_wake_irqs(void)
|
||||
*
|
||||
* Itereates over the list of device wakeirqs to arm them.
|
||||
*/
|
||||
void device_wakeup_arm_wake_irqs(void)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
if (ws->wakeirq)
|
||||
dev_pm_arm_wake_irq(ws->wakeirq);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_disarm_wake_irqs(void)
|
||||
*
|
||||
* Itereates over the list of device wakeirqs to disarm them.
|
||||
*/
|
||||
void device_wakeup_disarm_wake_irqs(void)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
if (ws->wakeirq)
|
||||
dev_pm_disarm_wake_irq(ws->wakeirq);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_detach - Detach a device's wakeup source object from it.
|
||||
* @dev: Device to detach the wakeup source object from.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user