782 lines
22 KiB
Diff
782 lines
22 KiB
Diff
From aed35270f0be1c5c61a028d7c183e60269f3abe3 Mon Sep 17 00:00:00 2001
|
|
From: Christophe Priouzeau <christophe.priouzeau@st.com>
|
|
Date: Mon, 26 Nov 2018 14:41:37 +0100
|
|
Subject: [PATCH 22/52] ARM-stm32mp1-r0-rc2-MFD-IRQ
|
|
|
|
---
|
|
.../interrupt-controller/st,stm32-exti.txt | 34 +++++-
|
|
.../devicetree/bindings/mfd/st,stpmic1.txt | 2 +-
|
|
Documentation/devicetree/bindings/mfd/syscon.txt | 1 +
|
|
drivers/irqchip/irq-stm32-exti.c | 133 ++++++++++++++++++---
|
|
drivers/mfd/stm32-pwr.c | 131 +++++++++-----------
|
|
drivers/mfd/stpmic1.c | 16 +--
|
|
drivers/mfd/syscon.c | 19 +++
|
|
drivers/mfd/wm8994-core.c | 15 +++
|
|
include/linux/mfd/stpmic1.h | 1 -
|
|
9 files changed, 247 insertions(+), 105 deletions(-)
|
|
|
|
diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
|
|
index 6a36bf6..abcf816 100644
|
|
--- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
|
|
+++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
|
|
@@ -14,7 +14,23 @@ Required properties:
|
|
(only needed for exti controller with multiple exti under
|
|
same parent interrupt: st,stm32-exti and st,stm32h7-exti)
|
|
|
|
-Example:
|
|
+Optional properties:
|
|
+
|
|
+- hwlocks: reference to a phandle of a hardware spinlock provider node.
|
|
+
|
|
+Exti could have several parent interrupt controllers. In this case child nodes
|
|
+are used to describe those "extra" parent controllers. Properties to use are:
|
|
+
|
|
+- interrupt-controller: Indentifies the node as an interrupt controller
|
|
+- #interrupt-cells: Specifies the number of cells to encode an interrupt
|
|
+ specifier, shall be 2
|
|
+- interrupt-parent: Phandle to the interrupt parent node.
|
|
+- st,irq-number: Interrupt number mapped on the parent.
|
|
+
|
|
+See example 2.
|
|
+
|
|
+
|
|
+Example 1:
|
|
|
|
exti: interrupt-controller@40013c00 {
|
|
compatible = "st,stm32-exti";
|
|
@@ -23,3 +39,19 @@ exti: interrupt-controller@40013c00 {
|
|
reg = <0x40013C00 0x400>;
|
|
interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>;
|
|
};
|
|
+
|
|
+Example 2:
|
|
+
|
|
+exti: interrupt-controller@5000d000 {
|
|
+ compatible = "st,stm32mp1-exti", "syscon";
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+ reg = <0x5000d000 0x400>;
|
|
+
|
|
+ exti_pwr: exti-pwr {
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+ interrupt-parent = <&pwr>;
|
|
+ st,irq-number = <6>;
|
|
+ };
|
|
+};
|
|
diff --git a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt
|
|
index 54b64e2..0fab08a 100644
|
|
--- a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt
|
|
+++ b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt
|
|
@@ -4,7 +4,6 @@ Required parent device properties:
|
|
- compatible: "st,stpmic1"
|
|
- reg: The I2C slave address for the STPMIC1 chip.
|
|
- interrupts: The interrupt lines the device is connected to.
|
|
- The second interrupt is used for wake-up.
|
|
- #interrupt-cells: Should be 2.
|
|
- interrupt-controller: Describes the STPMIC1 as an interrupt
|
|
controller (has its own domain). Interrupt number are the following:
|
|
@@ -81,6 +80,7 @@ Optional parent device properties:
|
|
-bit 5: SW_OUT discharge is enabled
|
|
-bit 6: VBUS_OTG detection is enabled
|
|
-bit 7: BOOST_OVP is disabled
|
|
+- wakeup-source: bool flag to indicate this device has wakeup capabilities
|
|
|
|
STPMIC1 consists in a varied group of sub-devices.
|
|
Each sub-device binding is be described in own documentation file.
|
|
diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt
|
|
index 25d9e9c..a9aaa51 100644
|
|
--- a/Documentation/devicetree/bindings/mfd/syscon.txt
|
|
+++ b/Documentation/devicetree/bindings/mfd/syscon.txt
|
|
@@ -17,6 +17,7 @@ Optional property:
|
|
- reg-io-width: the size (in bytes) of the IO accesses that should be
|
|
performed on the device.
|
|
- hwlocks: reference to a phandle of a hardware spinlock provider node.
|
|
+- clocks: phandle to the syscon clock
|
|
|
|
Examples:
|
|
gpr: iomuxc-gpr@20e0000 {
|
|
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
|
|
index e185ed8..9cc15f1 100644
|
|
--- a/drivers/irqchip/irq-stm32-exti.c
|
|
+++ b/drivers/irqchip/irq-stm32-exti.c
|
|
@@ -6,6 +6,7 @@
|
|
*/
|
|
|
|
#include <linux/bitops.h>
|
|
+#include <linux/hwspinlock.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
#include <linux/irq.h>
|
|
@@ -20,6 +21,8 @@
|
|
|
|
#define IRQS_PER_BANK 32
|
|
|
|
+#define HWSPINLOCK_TIMEOUT 5 /* msec */
|
|
+
|
|
struct stm32_exti_bank {
|
|
u32 imr_ofst;
|
|
u32 emr_ofst;
|
|
@@ -47,6 +50,7 @@ struct stm32_exti_drv_data {
|
|
struct stm32_exti_chip_data {
|
|
struct stm32_exti_host_data *host_data;
|
|
const struct stm32_exti_bank *reg_bank;
|
|
+ struct hwspinlock *hwlock;
|
|
struct raw_spinlock rlock;
|
|
u32 wake_active;
|
|
u32 mask_cache;
|
|
@@ -275,25 +279,34 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type)
|
|
struct stm32_exti_chip_data *chip_data = gc->private;
|
|
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
|
|
u32 rtsr, ftsr;
|
|
- int err;
|
|
+ int err = 0;
|
|
|
|
irq_gc_lock(gc);
|
|
|
|
+ if (chip_data->hwlock)
|
|
+ err = hwspin_lock_timeout(chip_data->hwlock,
|
|
+ HWSPINLOCK_TIMEOUT);
|
|
+
|
|
+ if (err)
|
|
+ goto unlock;
|
|
+
|
|
rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst);
|
|
ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst);
|
|
|
|
err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
|
|
- if (err) {
|
|
- irq_gc_unlock(gc);
|
|
- return err;
|
|
- }
|
|
+ if (err)
|
|
+ goto unspinlock;
|
|
|
|
irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst);
|
|
irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst);
|
|
|
|
+unspinlock:
|
|
+ if (chip_data->hwlock)
|
|
+ hwspin_unlock(chip_data->hwlock);
|
|
+unlock:
|
|
irq_gc_unlock(gc);
|
|
|
|
- return 0;
|
|
+ return err;
|
|
}
|
|
|
|
static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data,
|
|
@@ -457,22 +470,36 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
|
|
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
|
|
void __iomem *base = chip_data->host_data->base;
|
|
u32 rtsr, ftsr;
|
|
- int err;
|
|
+ int err = 0;
|
|
|
|
raw_spin_lock(&chip_data->rlock);
|
|
+
|
|
+ if (chip_data->hwlock)
|
|
+ err = hwspin_lock_timeout(chip_data->hwlock,
|
|
+ HWSPINLOCK_TIMEOUT);
|
|
+
|
|
+ if (err)
|
|
+ goto unlock;
|
|
+
|
|
rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst);
|
|
ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst);
|
|
|
|
err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
|
|
- if (err) {
|
|
- raw_spin_unlock(&chip_data->rlock);
|
|
- return err;
|
|
- }
|
|
+ if (err)
|
|
+ goto unspinlock;
|
|
|
|
writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst);
|
|
writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst);
|
|
+
|
|
+unspinlock:
|
|
+ if (chip_data->hwlock)
|
|
+ hwspin_unlock(chip_data->hwlock);
|
|
+unlock:
|
|
raw_spin_unlock(&chip_data->rlock);
|
|
|
|
+ if (d->parent_data->chip)
|
|
+ irq_chip_set_type_parent(d, type);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -490,6 +517,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on)
|
|
|
|
raw_spin_unlock(&chip_data->rlock);
|
|
|
|
+ if (d->parent_data->chip)
|
|
+ irq_chip_set_wake_parent(d, on);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -502,6 +532,12 @@ static int stm32_exti_h_set_affinity(struct irq_data *d,
|
|
return -EINVAL;
|
|
}
|
|
|
|
+static void stm32_exti_h_ack(struct irq_data *d)
|
|
+{
|
|
+ if (d->parent_data->chip)
|
|
+ irq_chip_ack_parent(d);
|
|
+}
|
|
+
|
|
#ifdef CONFIG_PM
|
|
static int stm32_exti_h_suspend(void)
|
|
{
|
|
@@ -547,6 +583,7 @@ static inline void stm32_exti_h_syscore_init(void) {}
|
|
static struct irq_chip stm32_exti_h_chip = {
|
|
.name = "stm32-exti-h",
|
|
.irq_eoi = stm32_exti_h_eoi,
|
|
+ .irq_ack = stm32_exti_h_ack,
|
|
.irq_mask = stm32_exti_h_mask,
|
|
.irq_unmask = stm32_exti_h_unmask,
|
|
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
|
@@ -574,15 +611,29 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm,
|
|
irq_domain_set_hwirq_and_chip(dm, virq, hwirq,
|
|
&stm32_exti_h_chip, chip_data);
|
|
|
|
- p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq);
|
|
- if (p_irq >= 0) {
|
|
+ /*
|
|
+ * EXTI 55 to 60 are mapped to PWR interrupt controller.
|
|
+ * The hwirq translation is done diferently than for GIC.
|
|
+ */
|
|
+ if (hwirq >= 55 && hwirq <= 60) {
|
|
p_fwspec.fwnode = dm->parent->fwnode;
|
|
- p_fwspec.param_count = 3;
|
|
- p_fwspec.param[0] = GIC_SPI;
|
|
- p_fwspec.param[1] = p_irq;
|
|
- p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
|
|
+ p_fwspec.param_count = 2;
|
|
+ p_fwspec.param[0] = hwirq - 55;
|
|
+ p_fwspec.param[1] = fwspec->param[1];
|
|
|
|
return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec);
|
|
+ } else {
|
|
+ p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq);
|
|
+ if (p_irq >= 0) {
|
|
+ p_fwspec.fwnode = dm->parent->fwnode;
|
|
+ p_fwspec.param_count = 3;
|
|
+ p_fwspec.param[0] = GIC_SPI;
|
|
+ p_fwspec.param[1] = p_irq;
|
|
+ p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
|
|
+
|
|
+ return irq_domain_alloc_irqs_parent(dm, virq, 1,
|
|
+ &p_fwspec);
|
|
+ }
|
|
}
|
|
|
|
return 0;
|
|
@@ -665,6 +716,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
|
|
int nr_irqs, ret, i;
|
|
struct irq_chip_generic *gc;
|
|
struct irq_domain *domain;
|
|
+ struct hwspinlock *hwlock = NULL;
|
|
|
|
host_data = stm32_exti_host_init(drv_data, node);
|
|
if (!host_data)
|
|
@@ -687,12 +739,22 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
|
|
goto out_free_domain;
|
|
}
|
|
|
|
+ /* hwspinlock is optional */
|
|
+ ret = of_hwspin_lock_get_id(node, 0);
|
|
+ if (ret < 0) {
|
|
+ if (ret == -EPROBE_DEFER)
|
|
+ goto out_free_domain;
|
|
+ } else {
|
|
+ hwlock = hwspin_lock_request_specific(ret);
|
|
+ }
|
|
+
|
|
for (i = 0; i < drv_data->bank_nr; i++) {
|
|
const struct stm32_exti_bank *stm32_bank;
|
|
struct stm32_exti_chip_data *chip_data;
|
|
|
|
stm32_bank = drv_data->exti_banks[i];
|
|
chip_data = stm32_exti_chip_init(host_data, i, node);
|
|
+ chip_data->hwlock = hwlock;
|
|
|
|
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
|
|
|
|
@@ -760,11 +822,12 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
|
|
{
|
|
struct irq_domain *parent_domain, *domain;
|
|
struct stm32_exti_host_data *host_data;
|
|
+ struct device_node *child;
|
|
int ret, i;
|
|
|
|
parent_domain = irq_find_host(parent);
|
|
if (!parent_domain) {
|
|
- pr_err("interrupt-parent not found\n");
|
|
+ pr_err("GIC interrupt-parent not found\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
@@ -786,6 +849,40 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
|
|
goto out_unmap;
|
|
}
|
|
|
|
+ for_each_child_of_node(node, child) {
|
|
+ struct device_node *parent_node;
|
|
+ u32 nirqs;
|
|
+
|
|
+ parent_node = of_irq_find_parent(child);
|
|
+ parent_domain = irq_find_host(parent_node);
|
|
+
|
|
+ if (!parent_domain) {
|
|
+ pr_err("%s: child interrupt-parent not found\n",
|
|
+ child->name);
|
|
+ ret = -EINVAL;
|
|
+ goto out_unmap;
|
|
+ }
|
|
+
|
|
+ ret = of_property_read_u32(child, "st,irq-number", &nirqs);
|
|
+ if (ret != 0 || nirqs == 0) {
|
|
+ pr_err("%s: Missing or bad irq-number property\n"
|
|
+ , __func__);
|
|
+ ret = -EINVAL;
|
|
+ goto out_unmap;
|
|
+ }
|
|
+
|
|
+ domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs,
|
|
+ child,
|
|
+ &stm32_exti_h_domain_ops,
|
|
+ host_data);
|
|
+ if (!domain) {
|
|
+ pr_err("%s: Could not register exti domain.\n",
|
|
+ node->name);
|
|
+ ret = -ENOMEM;
|
|
+ goto out_unmap;
|
|
+ }
|
|
+ }
|
|
+
|
|
stm32_exti_h_syscore_init();
|
|
|
|
return 0;
|
|
diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c
|
|
index 377e2f5..206a933 100644
|
|
--- a/drivers/mfd/stm32-pwr.c
|
|
+++ b/drivers/mfd/stm32-pwr.c
|
|
@@ -5,7 +5,9 @@
|
|
*/
|
|
|
|
#include <linux/arm-smccc.h>
|
|
+#include <linux/irqchip.h>
|
|
#include <linux/irqchip/chained_irq.h>
|
|
+#include <linux/of_address.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/platform_device.h>
|
|
#include <asm/exception.h>
|
|
@@ -45,7 +47,6 @@ enum wkup_pull_setting {
|
|
} \
|
|
|
|
struct stm32_pwr_data {
|
|
- struct device *dev; /* self device */
|
|
void __iomem *base; /* IO Memory base address */
|
|
struct irq_domain *domain; /* Domain for this controller */
|
|
int irq; /* Parent interrupt */
|
|
@@ -53,25 +54,19 @@ struct stm32_pwr_data {
|
|
|
|
static void stm32_pwr_irq_ack(struct irq_data *d)
|
|
{
|
|
- struct stm32_pwr_data *priv = d->domain->host_data;
|
|
-
|
|
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
|
|
+ pr_debug("irq:%lu\n", d->hwirq);
|
|
SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, BIT(d->hwirq));
|
|
}
|
|
|
|
static void stm32_pwr_irq_mask(struct irq_data *d)
|
|
{
|
|
- struct stm32_pwr_data *priv = d->domain->host_data;
|
|
-
|
|
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
|
|
+ pr_debug("irq:%lu\n", d->hwirq);
|
|
SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, BIT(d->hwirq));
|
|
}
|
|
|
|
static void stm32_pwr_irq_unmask(struct irq_data *d)
|
|
{
|
|
- struct stm32_pwr_data *priv = d->domain->host_data;
|
|
-
|
|
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
|
|
+ pr_debug("irq:%lu\n", d->hwirq);
|
|
SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq));
|
|
}
|
|
|
|
@@ -79,7 +74,7 @@ static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on)
|
|
{
|
|
struct stm32_pwr_data *priv = d->domain->host_data;
|
|
|
|
- dev_dbg(priv->dev, "irq:%lu on:%d\n", d->hwirq, on);
|
|
+ pr_debug("irq:%lu on:%d\n", d->hwirq, on);
|
|
if (on)
|
|
enable_irq_wake(priv->irq);
|
|
else
|
|
@@ -95,7 +90,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
|
u32 wkupcr;
|
|
int en;
|
|
|
|
- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq);
|
|
+ pr_debug("irq:%lu\n", d->hwirq);
|
|
|
|
en = readl_relaxed(priv->base + MPUWKUPENR) & BIT(pin_id);
|
|
/* reference manual request to disable the wakeup pin while
|
|
@@ -115,6 +110,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
+
|
|
SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr);
|
|
|
|
if (en)
|
|
@@ -124,7 +120,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
|
}
|
|
|
|
static struct irq_chip stm32_pwr_irq_chip = {
|
|
- .name = "stm32_pwr-irq",
|
|
+ .name = "stm32-pwr-irq",
|
|
.irq_ack = stm32_pwr_irq_ack,
|
|
.irq_mask = stm32_pwr_irq_mask,
|
|
.irq_unmask = stm32_pwr_irq_unmask,
|
|
@@ -132,29 +128,23 @@ static struct irq_chip stm32_pwr_irq_chip = {
|
|
.irq_set_wake = stm32_pwr_irq_set_wake,
|
|
};
|
|
|
|
-static int stm32_pwr_irq_map(struct irq_domain *h, unsigned int virq,
|
|
- irq_hw_number_t hw)
|
|
-{
|
|
- irq_set_chip_and_handler(virq, &stm32_pwr_irq_chip, handle_edge_irq);
|
|
- return 0;
|
|
-}
|
|
-
|
|
static int stm32_pwr_irq_set_pull_config(struct irq_domain *d, int pin_id,
|
|
enum wkup_pull_setting config)
|
|
{
|
|
struct stm32_pwr_data *priv = d->host_data;
|
|
u32 wkupcr;
|
|
|
|
- dev_dbg(priv->dev, "irq:%d pull config:0x%x\n", pin_id, config);
|
|
+ pr_debug("irq:%d pull config:0x%x\n", pin_id, config);
|
|
|
|
if (config >= WKUP_PULL_RESERVED) {
|
|
- dev_err(priv->dev, "%s: bad irq pull config\n", __func__);
|
|
+ pr_err("%s: bad irq pull config\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
wkupcr = readl_relaxed(priv->base + WKUPCR);
|
|
wkupcr &= ~((WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2));
|
|
wkupcr |= (config & WKUP_PULL_MASK) << (WKUP_PULL_SHIFT + pin_id * 2);
|
|
+
|
|
SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr);
|
|
|
|
return 0;
|
|
@@ -164,10 +154,8 @@ static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr,
|
|
const u32 *intspec, unsigned int intsize,
|
|
irq_hw_number_t *out_hwirq, unsigned int *out_type)
|
|
{
|
|
- struct stm32_pwr_data *priv = d->host_data;
|
|
-
|
|
if (WARN_ON(intsize < 3)) {
|
|
- dev_err(priv->dev, "%s: bad irq config parameters\n", __func__);
|
|
+ pr_err("%s: bad irq config parameters\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
@@ -177,9 +165,23 @@ static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr,
|
|
return stm32_pwr_irq_set_pull_config(d, intspec[0], intspec[2]);
|
|
}
|
|
|
|
+static int stm32_pwr_alloc(struct irq_domain *d, unsigned int virq,
|
|
+ unsigned int nr_irqs, void *data)
|
|
+{
|
|
+ struct irq_fwspec *fwspec = data;
|
|
+ irq_hw_number_t hwirq;
|
|
+
|
|
+ hwirq = fwspec->param[0];
|
|
+ irq_domain_set_info(d, virq, hwirq, &stm32_pwr_irq_chip, d->host_data,
|
|
+ handle_edge_irq, NULL, NULL);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct irq_domain_ops stm32_pwr_irq_domain_ops = {
|
|
- .map = stm32_pwr_irq_map,
|
|
+ .alloc = stm32_pwr_alloc,
|
|
.xlate = stm32_pwr_xlate,
|
|
+ .free = irq_domain_free_irqs_common,
|
|
};
|
|
|
|
/*
|
|
@@ -195,9 +197,10 @@ static void stm32_pwr_handle_irq(struct irq_desc *desc)
|
|
|
|
wkupfr = readl_relaxed(priv->base + WKUPFR);
|
|
wkupenr = readl_relaxed(priv->base + MPUWKUPENR);
|
|
+
|
|
for (i = 0; i < NB_WAKEUPPINS; i++) {
|
|
if ((wkupfr & BIT(i)) && (wkupenr & BIT(i))) {
|
|
- dev_dbg(priv->dev, "handle wkup irq:%d\n", i);
|
|
+ pr_debug("handle wkup irq:%d\n", i);
|
|
generic_handle_irq(irq_find_mapping(priv->domain, i));
|
|
}
|
|
}
|
|
@@ -205,27 +208,21 @@ static void stm32_pwr_handle_irq(struct irq_desc *desc)
|
|
chained_irq_exit(chip, desc);
|
|
}
|
|
|
|
-static int stm32_pwr_probe(struct platform_device *pdev)
|
|
+static int __init stm32_pwr_init(struct device_node *np,
|
|
+ struct device_node *parent)
|
|
{
|
|
- struct device *dev = &pdev->dev;
|
|
- struct device_node *np = pdev->dev.of_node;
|
|
struct stm32_pwr_data *priv;
|
|
-
|
|
- struct resource *res;
|
|
int ret;
|
|
|
|
- priv = devm_kzalloc(dev, sizeof(struct stm32_pwr_data), GFP_KERNEL);
|
|
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
|
|
- platform_set_drvdata(pdev, priv);
|
|
- priv->dev = dev;
|
|
-
|
|
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
- priv->base = devm_ioremap_resource(&pdev->dev, res);
|
|
+ priv->base = of_iomap(np, 0);
|
|
if (IS_ERR(priv->base)) {
|
|
- dev_err(dev, "%s: Unable to map IO memory\n", __func__);
|
|
- return PTR_ERR(priv->base);
|
|
+ pr_err("%s: Unable to map IO memory\n", __func__);
|
|
+ ret = PTR_ERR(priv->base);
|
|
+ goto out_free;
|
|
}
|
|
|
|
/* Disable all wake-up pins */
|
|
@@ -236,52 +233,38 @@ static int stm32_pwr_probe(struct platform_device *pdev)
|
|
priv->domain = irq_domain_add_linear(np, NB_WAKEUPPINS,
|
|
&stm32_pwr_irq_domain_ops, priv);
|
|
if (!priv->domain) {
|
|
- dev_err(dev, "%s: Unable to add irq domain!\n", __func__);
|
|
- goto out;
|
|
+ pr_err("%s: Unable to add irq domain!\n", __func__);
|
|
+ ret = -ENOMEM;
|
|
+ goto out_unmap;
|
|
}
|
|
|
|
- ret = platform_get_irq(pdev, 0);
|
|
- if (ret < 0) {
|
|
- dev_err(dev, "failed to get PWR IRQ\n");
|
|
- goto err;
|
|
+ priv->irq = irq_of_parse_and_map(np, 0);
|
|
+ if (priv->irq < 0) {
|
|
+ pr_err("failed to get PWR IRQ\n");
|
|
+ ret = priv->irq;
|
|
+ goto out_domain;
|
|
}
|
|
- priv->irq = ret;
|
|
|
|
irq_set_chained_handler_and_data(priv->irq,
|
|
stm32_pwr_handle_irq, priv);
|
|
|
|
-out:
|
|
+ of_node_clear_flag(np, OF_POPULATED);
|
|
+
|
|
return 0;
|
|
-err:
|
|
+
|
|
+out_domain:
|
|
irq_domain_remove(priv->domain);
|
|
+out_unmap:
|
|
+ iounmap(priv->base);
|
|
+out_free:
|
|
+ kfree(priv);
|
|
return ret;
|
|
}
|
|
|
|
-static int stm32_pwr_remove(struct platform_device *pdev)
|
|
+static int __init stm32_pwr_of_init(struct device_node *np,
|
|
+ struct device_node *parent)
|
|
{
|
|
- struct stm32_pwr_data *priv = platform_get_drvdata(pdev);
|
|
-
|
|
- irq_domain_remove(priv->domain);
|
|
- return 0;
|
|
+ return stm32_pwr_init(np, parent);
|
|
}
|
|
|
|
-static const struct of_device_id stm32_pwr_match[] = {
|
|
- { .compatible = "st,stm32mp1-pwr" },
|
|
- {},
|
|
-};
|
|
-
|
|
-static struct platform_driver stm32_pwr_driver = {
|
|
- .probe = stm32_pwr_probe,
|
|
- .remove = stm32_pwr_remove,
|
|
- .driver = {
|
|
- .name = "stm32-pwr",
|
|
- .owner = THIS_MODULE,
|
|
- .of_match_table = stm32_pwr_match,
|
|
- },
|
|
-};
|
|
-
|
|
-static int __init stm32_pwr_init(void)
|
|
-{
|
|
- return platform_driver_register(&stm32_pwr_driver);
|
|
-}
|
|
-arch_initcall(stm32_pwr_init);
|
|
+IRQCHIP_DECLARE(stm32mp1_pwr_irq, "st,stm32mp1-pwr", stm32_pwr_of_init);
|
|
diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c
|
|
index 5bf6328..648315d 100644
|
|
--- a/drivers/mfd/stpmic1.c
|
|
+++ b/drivers/mfd/stpmic1.c
|
|
@@ -268,13 +268,8 @@ static int stpmic1_probe(struct i2c_client *i2c,
|
|
return ddata->irq;
|
|
}
|
|
|
|
- ddata->irq_wake = of_irq_get(np, STPMIC1_WAKEUP_IRQ);
|
|
- if (ddata->irq_wake > 0) {
|
|
+ if (of_property_read_bool(np, "wakeup-source"))
|
|
device_init_wakeup(dev, true);
|
|
- ret = dev_pm_set_dedicated_wake_irq(dev, ddata->irq_wake);
|
|
- if (ret)
|
|
- dev_warn(dev, "failed to set up wakeup irq");
|
|
- }
|
|
|
|
if (!of_property_read_u32(np, "st,main-control-register", ®)) {
|
|
ret = regmap_update_bits(ddata->regmap,
|
|
@@ -371,8 +366,8 @@ static int stpmic1_suspend(struct device *dev)
|
|
struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c);
|
|
|
|
disable_irq(pmic_dev->irq);
|
|
- if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev))
|
|
- enable_irq_wake(pmic_dev->irq_wake);
|
|
+ if (device_may_wakeup(dev))
|
|
+ enable_irq_wake(pmic_dev->irq);
|
|
|
|
return 0;
|
|
}
|
|
@@ -387,9 +382,10 @@ static int stpmic1_resume(struct device *dev)
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ if (device_may_wakeup(dev))
|
|
+ disable_irq_wake(pmic_dev->irq);
|
|
+
|
|
enable_irq(pmic_dev->irq);
|
|
- if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev))
|
|
- disable_irq_wake(pmic_dev->irq_wake);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
|
|
index b6d05cd..a0ba4ff 100644
|
|
--- a/drivers/mfd/syscon.c
|
|
+++ b/drivers/mfd/syscon.c
|
|
@@ -12,6 +12,7 @@
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
+#include <linux/clk.h>
|
|
#include <linux/err.h>
|
|
#include <linux/hwspinlock.h>
|
|
#include <linux/io.h>
|
|
@@ -45,6 +46,7 @@ static const struct regmap_config syscon_regmap_config = {
|
|
|
|
static struct syscon *of_syscon_register(struct device_node *np)
|
|
{
|
|
+ struct clk *clk;
|
|
struct syscon *syscon;
|
|
struct regmap *regmap;
|
|
void __iomem *base;
|
|
@@ -119,6 +121,18 @@ static struct syscon *of_syscon_register(struct device_node *np)
|
|
goto err_regmap;
|
|
}
|
|
|
|
+ clk = of_clk_get(np, 0);
|
|
+ if (IS_ERR(clk)) {
|
|
+ ret = PTR_ERR(clk);
|
|
+ /* clock is optional */
|
|
+ if (ret != -ENOENT)
|
|
+ goto err_clk;
|
|
+ } else {
|
|
+ ret = regmap_mmio_attach_clk(regmap, clk);
|
|
+ if (ret)
|
|
+ goto err_attach;
|
|
+ }
|
|
+
|
|
syscon->regmap = regmap;
|
|
syscon->np = np;
|
|
|
|
@@ -128,6 +142,11 @@ static struct syscon *of_syscon_register(struct device_node *np)
|
|
|
|
return syscon;
|
|
|
|
+err_attach:
|
|
+ if (!IS_ERR(clk))
|
|
+ clk_put(clk);
|
|
+err_clk:
|
|
+ regmap_exit(regmap);
|
|
err_regmap:
|
|
iounmap(base);
|
|
err_map:
|
|
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
|
|
index 22bd652..755863a 100644
|
|
--- a/drivers/mfd/wm8994-core.c
|
|
+++ b/drivers/mfd/wm8994-core.c
|
|
@@ -12,6 +12,7 @@
|
|
*
|
|
*/
|
|
|
|
+#include <linux/clk.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
@@ -314,6 +315,20 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994)
|
|
if (pdata->ldo[1].enable < 0)
|
|
pdata->ldo[1].enable = 0;
|
|
|
|
+ pdata->mclk1 = devm_clk_get(wm8994->dev, "MCLK1");
|
|
+ if (IS_ERR(pdata->mclk1)) {
|
|
+ if (PTR_ERR(pdata->mclk1) != -ENOENT)
|
|
+ return PTR_ERR(pdata->mclk1);
|
|
+ pdata->mclk1 = NULL;
|
|
+ }
|
|
+
|
|
+ pdata->mclk2 = devm_clk_get(wm8994->dev, "MCLK2");
|
|
+ if (IS_ERR(pdata->mclk2)) {
|
|
+ if (PTR_ERR(pdata->mclk2) != -ENOENT)
|
|
+ return PTR_ERR(pdata->mclk2);
|
|
+ pdata->mclk2 = NULL;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
#else
|
|
diff --git a/include/linux/mfd/stpmic1.h b/include/linux/mfd/stpmic1.h
|
|
index 4abe5f1..fa3f99f 100644
|
|
--- a/include/linux/mfd/stpmic1.h
|
|
+++ b/include/linux/mfd/stpmic1.h
|
|
@@ -206,7 +206,6 @@ struct stpmic1 {
|
|
struct device *dev;
|
|
struct regmap *regmap;
|
|
int irq;
|
|
- int irq_wake;
|
|
struct regmap_irq_chip_data *irq_data;
|
|
};
|
|
|
|
--
|
|
2.7.4
|
|
|