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", &reg)) {
 		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

