mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 17:12:06 +00:00
Merge branch 'irqchip/stacked-exynos' into irqchip/core
This commit is contained in:
commit
fb414e908b
@ -29,10 +29,27 @@ Properties:
|
||||
- clocks : list of phandles and specifiers to all input clocks listed in
|
||||
clock-names property.
|
||||
|
||||
Optional properties:
|
||||
|
||||
Some PMUs are capable of behaving as an interrupt controller (mostly
|
||||
to wake up a suspended PMU). In which case, they can have the
|
||||
following properties:
|
||||
|
||||
- interrupt-controller: indicate that said PMU is an interrupt controller
|
||||
|
||||
- #interrupt-cells: must be identical to the that of the parent interrupt
|
||||
controller.
|
||||
|
||||
- interrupt-parent: a phandle indicating which interrupt controller
|
||||
this PMU signals interrupts to.
|
||||
|
||||
Example :
|
||||
pmu_system_controller: system-controller@10040000 {
|
||||
compatible = "samsung,exynos5250-pmu", "syscon";
|
||||
reg = <0x10040000 0x5000>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <3>;
|
||||
interrupt-parent = <&gic>;
|
||||
#clock-cells = <1>;
|
||||
clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
|
||||
"clkout4", "clkout8", "clkout9";
|
||||
|
@ -130,6 +130,9 @@
|
||||
pmu_system_controller: system-controller@10020000 {
|
||||
compatible = "samsung,exynos3250-pmu", "syscon";
|
||||
reg = <0x10020000 0x4000>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <3>;
|
||||
interrupt-parent = <&gic>;
|
||||
};
|
||||
|
||||
mipi_phy: video-phy@10020710 {
|
||||
@ -184,6 +187,7 @@
|
||||
compatible = "samsung,exynos3250-rtc";
|
||||
reg = <0x10070000 0x100>;
|
||||
interrupts = <0 73 0>, <0 74 0>;
|
||||
interrupt-parent = <&pmu_system_controller>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -152,6 +152,9 @@
|
||||
pmu_system_controller: system-controller@10020000 {
|
||||
compatible = "samsung,exynos4210-pmu", "syscon";
|
||||
reg = <0x10020000 0x4000>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <3>;
|
||||
interrupt-parent = <&gic>;
|
||||
};
|
||||
|
||||
dsi_0: dsi@11C80000 {
|
||||
@ -264,6 +267,7 @@
|
||||
rtc@10070000 {
|
||||
compatible = "samsung,s3c6410-rtc";
|
||||
reg = <0x10070000 0x100>;
|
||||
interrupt-parent = <&pmu_system_controller>;
|
||||
interrupts = <0 44 0>, <0 45 0>;
|
||||
clocks = <&clock CLK_RTC>;
|
||||
clock-names = "rtc";
|
||||
|
@ -196,6 +196,9 @@
|
||||
clock-names = "clkout16";
|
||||
clocks = <&clock CLK_FIN_PLL>;
|
||||
#clock-cells = <1>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <3>;
|
||||
interrupt-parent = <&gic>;
|
||||
};
|
||||
|
||||
sysreg_system_controller: syscon@10050000 {
|
||||
@ -232,6 +235,7 @@
|
||||
rtc: rtc@101E0000 {
|
||||
clocks = <&clock CLK_RTC>;
|
||||
clock-names = "rtc";
|
||||
interrupt-parent = <&pmu_system_controller>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -327,6 +327,7 @@
|
||||
rtc: rtc@101E0000 {
|
||||
clocks = <&clock CLK_RTC>;
|
||||
clock-names = "rtc";
|
||||
interrupt-parent = <&pmu_system_controller>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@ -769,6 +770,9 @@
|
||||
clock-names = "clkout16";
|
||||
clocks = <&clock CLK_FIN_PLL>;
|
||||
#clock-cells = <1>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <3>;
|
||||
interrupt-parent = <&gic>;
|
||||
};
|
||||
|
||||
sysreg_system_controller: syscon@10050000 {
|
||||
|
@ -166,16 +166,14 @@ static void __init exynos_init_io(void)
|
||||
exynos_map_io();
|
||||
}
|
||||
|
||||
/*
|
||||
* Apparently, these SoCs are not able to wake-up from suspend using
|
||||
* the PMU. Too bad. Should they suddenly become capable of such a
|
||||
* feat, the matches below should be moved to suspend.c.
|
||||
*/
|
||||
static const struct of_device_id exynos_dt_pmu_match[] = {
|
||||
{ .compatible = "samsung,exynos3250-pmu" },
|
||||
{ .compatible = "samsung,exynos4210-pmu" },
|
||||
{ .compatible = "samsung,exynos4212-pmu" },
|
||||
{ .compatible = "samsung,exynos4412-pmu" },
|
||||
{ .compatible = "samsung,exynos4415-pmu" },
|
||||
{ .compatible = "samsung,exynos5250-pmu" },
|
||||
{ .compatible = "samsung,exynos5260-pmu" },
|
||||
{ .compatible = "samsung,exynos5410-pmu" },
|
||||
{ .compatible = "samsung,exynos5420-pmu" },
|
||||
{ /*sentinel*/ },
|
||||
};
|
||||
|
||||
@ -186,9 +184,6 @@ static void exynos_map_pmu(void)
|
||||
np = of_find_matching_node(NULL, exynos_dt_pmu_match);
|
||||
if (np)
|
||||
pmu_base_addr = of_iomap(np, 0);
|
||||
|
||||
if (!pmu_base_addr)
|
||||
panic("failed to find exynos pmu register\n");
|
||||
}
|
||||
|
||||
static void __init exynos_init_irq(void)
|
||||
|
@ -18,7 +18,9 @@
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
@ -43,8 +45,8 @@
|
||||
#define EXYNOS5420_CPU_STATE 0x28
|
||||
|
||||
/**
|
||||
* struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping
|
||||
* @hwirq: Hardware IRQ signal of the GIC
|
||||
* struct exynos_wkup_irq - PMU IRQ to mask mapping
|
||||
* @hwirq: Hardware IRQ signal of the PMU
|
||||
* @mask: Mask in PMU wake-up mask register
|
||||
*/
|
||||
struct exynos_wkup_irq {
|
||||
@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
|
||||
};
|
||||
|
||||
static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
|
||||
{ 76, BIT(1) }, /* RTC alarm */
|
||||
{ 77, BIT(2) }, /* RTC tick */
|
||||
{ 44, BIT(1) }, /* RTC alarm */
|
||||
{ 45, BIT(2) }, /* RTC tick */
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
|
||||
{ 75, BIT(1) }, /* RTC alarm */
|
||||
{ 76, BIT(2) }, /* RTC tick */
|
||||
{ 43, BIT(1) }, /* RTC alarm */
|
||||
{ 44, BIT(2) }, /* RTC tick */
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
@ -167,6 +169,113 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static struct irq_chip exynos_pmu_chip = {
|
||||
.name = "PMU",
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_mask = irq_chip_mask_parent,
|
||||
.irq_unmask = irq_chip_unmask_parent,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_set_wake = exynos_irq_set_wake,
|
||||
#ifdef CONFIG_SMP
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int exynos_pmu_domain_xlate(struct irq_domain *domain,
|
||||
struct device_node *controller,
|
||||
const u32 *intspec,
|
||||
unsigned int intsize,
|
||||
unsigned long *out_hwirq,
|
||||
unsigned int *out_type)
|
||||
{
|
||||
if (domain->of_node != controller)
|
||||
return -EINVAL; /* Shouldn't happen, really... */
|
||||
if (intsize != 3)
|
||||
return -EINVAL; /* Not GIC compliant */
|
||||
if (intspec[0] != 0)
|
||||
return -EINVAL; /* No PPI should point to this domain */
|
||||
|
||||
*out_hwirq = intspec[1];
|
||||
*out_type = intspec[2];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_pmu_domain_alloc(struct irq_domain *domain,
|
||||
unsigned int virq,
|
||||
unsigned int nr_irqs, void *data)
|
||||
{
|
||||
struct of_phandle_args *args = data;
|
||||
struct of_phandle_args parent_args;
|
||||
irq_hw_number_t hwirq;
|
||||
int i;
|
||||
|
||||
if (args->args_count != 3)
|
||||
return -EINVAL; /* Not GIC compliant */
|
||||
if (args->args[0] != 0)
|
||||
return -EINVAL; /* No PPI should point to this domain */
|
||||
|
||||
hwirq = args->args[1];
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
|
||||
&exynos_pmu_chip, NULL);
|
||||
|
||||
parent_args = *args;
|
||||
parent_args.np = domain->parent->of_node;
|
||||
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops exynos_pmu_domain_ops = {
|
||||
.xlate = exynos_pmu_domain_xlate,
|
||||
.alloc = exynos_pmu_domain_alloc,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
};
|
||||
|
||||
static int __init exynos_pmu_irq_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *parent_domain, *domain;
|
||||
|
||||
if (!parent) {
|
||||
pr_err("%s: no parent, giving up\n", node->full_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
parent_domain = irq_find_host(parent);
|
||||
if (!parent_domain) {
|
||||
pr_err("%s: unable to obtain parent domain\n", node->full_name);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
pmu_base_addr = of_iomap(node, 0);
|
||||
|
||||
if (!pmu_base_addr) {
|
||||
pr_err("%s: failed to find exynos pmu register\n",
|
||||
node->full_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
domain = irq_domain_add_hierarchy(parent_domain, 0, 0,
|
||||
node, &exynos_pmu_domain_ops,
|
||||
NULL);
|
||||
if (!domain) {
|
||||
iounmap(pmu_base_addr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EXYNOS_PMU_IRQ(symbol, name) OF_DECLARE_2(irqchip, symbol, name, exynos_pmu_irq_init)
|
||||
|
||||
EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
|
||||
EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
|
||||
EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu");
|
||||
EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu");
|
||||
EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu");
|
||||
EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu");
|
||||
EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu");
|
||||
|
||||
static int exynos_cpu_do_idle(void)
|
||||
{
|
||||
/* issue the standby signal into the pm unit. */
|
||||
@ -615,17 +724,19 @@ static struct syscore_ops exynos_pm_syscore_ops;
|
||||
void __init exynos_pm_init(void)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device_node *np;
|
||||
u32 tmp;
|
||||
|
||||
of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match);
|
||||
if (!match) {
|
||||
np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match);
|
||||
if (!np) {
|
||||
pr_err("Failed to find PMU node\n");
|
||||
return;
|
||||
}
|
||||
pm_data = (struct exynos_pm_data *) match->data;
|
||||
|
||||
/* Platform-specific GIC callback */
|
||||
gic_arch_extn.irq_set_wake = exynos_irq_set_wake;
|
||||
if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL)))
|
||||
pr_warn("Outdated DT detected, suspend/resume will NOT work\n");
|
||||
|
||||
pm_data = (struct exynos_pm_data *) match->data;
|
||||
|
||||
/* All wakeup disable */
|
||||
tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
|
||||
|
Loading…
Reference in New Issue
Block a user