All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
To: Nicolas Ferre <nicolas.ferre@atmel.com>,
	Boris Brezillon <boris.brezillon@free-electrons.com>
Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@codeaurora.org>,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-clk@vger.kernel.org,
	Alexandre Belloni <alexandre.belloni@free-electrons.com>
Subject: [PATCH v2 05/14] clk: at91: make IRQ optional and register them later
Date: Mon, 12 Oct 2015 16:28:42 +0200	[thread overview]
Message-ID: <1444660131-14954-6-git-send-email-alexandre.belloni@free-electrons.com> (raw)
In-Reply-To: <1444660131-14954-1-git-send-email-alexandre.belloni@free-electrons.com>

The AT91 clock drivers make use of IRQs to avoid polling when waiting for
some clocks to be enabled. Unfortunately, this leads to a crash when those
IRQs are threaded (which happens when using preempt-rt) because they are
registered before thread creation is possible.

Use polling on those clocks until the IRQ is registered and register the
IRQ at module probe time.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 drivers/clk/at91/clk-main.c   | 152 ++++++++++++++++++++++--------------------
 drivers/clk/at91/clk-master.c |  74 ++++++++++++++------
 drivers/clk/at91/clk-pll.c    |  75 +++++++++++++++------
 drivers/clk/at91/clk-system.c |  79 +++++++++++++++-------
 drivers/clk/at91/clk-utmi.c   |  75 ++++++++++++++-------
 drivers/clk/at91/pmc.c        |  98 ++++++++++++---------------
 6 files changed, 336 insertions(+), 217 deletions(-)

diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 5841eb958f83..4b021714e801 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -22,6 +23,8 @@
 #include <linux/regmap.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include "pmc.h"
 
@@ -110,9 +113,13 @@ static int clk_main_osc_prepare(struct clk_hw *hw)
 	}
 
 	while (!clk_main_osc_ready(regmap)) {
-		enable_irq(osc->base.irq);
-		wait_event(osc->base.wait,
-			   clk_main_osc_ready(regmap));
+		if (osc->base.irq) {
+			enable_irq(osc->base.irq);
+			wait_event(osc->base.wait,
+				   clk_main_osc_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -158,17 +165,15 @@ static const struct clk_ops main_osc_ops = {
 
 static struct clk * __init
 at91_clk_register_main_osc(struct regmap *regmap,
-			   unsigned int irq,
 			   const char *name,
 			   const char *parent_name,
 			   bool bypass)
 {
-	int ret;
 	struct clk_main_osc *osc;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
 
-	if (!irq || !name || !parent_name)
+	if (!name || !parent_name)
 		return ERR_PTR(-EINVAL);
 
 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
@@ -183,16 +188,6 @@ at91_clk_register_main_osc(struct regmap *regmap,
 
 	osc->base.hw.init = &init;
 	osc->base.regmap = regmap;
-	osc->base.irq = irq;
-
-	init_waitqueue_head(&osc->base.wait);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = request_irq(irq, clk_main_irq_handler,
-			  IRQF_TRIGGER_HIGH, name, &osc->base);
-	if (ret) {
-		kfree(osc);
-		return ERR_PTR(ret);
-	}
 
 	if (bypass)
 		regmap_update_bits(regmap,
@@ -201,10 +196,8 @@ at91_clk_register_main_osc(struct regmap *regmap,
 				   AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
 
 	clk = clk_register(NULL, &osc->base.hw);
-	if (IS_ERR(clk)) {
-		free_irq(irq, osc);
+	if (IS_ERR(clk))
 		kfree(osc);
-	}
 
 	return clk;
 }
@@ -212,7 +205,6 @@ at91_clk_register_main_osc(struct regmap *regmap,
 static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
 {
 	struct clk *clk;
-	unsigned int irq;
 	const char *name = np->name;
 	const char *parent_name;
 	struct regmap *regmap;
@@ -226,11 +218,7 @@ static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
 	if (IS_ERR(regmap))
 		return;
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
-	clk = at91_clk_register_main_osc(regmap, irq, name, parent_name, bypass);
+	clk = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
 	if (IS_ERR(clk))
 		return;
 
@@ -262,9 +250,13 @@ static int clk_main_rc_osc_prepare(struct clk_hw *hw)
 				   AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
 
 	while (!clk_main_rc_osc_ready(regmap)) {
-		enable_irq(osc->base.irq);
-		wait_event(osc->base.wait,
-			   clk_main_rc_osc_ready(regmap));
+		if (osc->base.irq) {
+			enable_irq(osc->base.irq);
+			wait_event(osc->base.wait,
+				   clk_main_rc_osc_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -323,11 +315,9 @@ static const struct clk_ops main_rc_osc_ops = {
 
 static struct clk * __init
 at91_clk_register_main_rc_osc(struct regmap *regmap,
-			      unsigned int irq,
 			      const char *name,
 			      u32 frequency, u32 accuracy)
 {
-	int ret;
 	struct clk_main_rc_osc *osc;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -347,22 +337,12 @@ at91_clk_register_main_rc_osc(struct regmap *regmap,
 
 	osc->base.hw.init = &init;
 	osc->base.regmap = regmap;
-	osc->base.irq = irq;
 	osc->frequency = frequency;
 	osc->accuracy = accuracy;
 
-	init_waitqueue_head(&osc->base.wait);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = request_irq(irq, clk_main_irq_handler,
-			  IRQF_TRIGGER_HIGH, name, &osc->base);
-	if (ret)
-		return ERR_PTR(ret);
-
 	clk = clk_register(NULL, &osc->base.hw);
-	if (IS_ERR(clk)) {
-		free_irq(irq, osc);
+	if (IS_ERR(clk))
 		kfree(osc);
-	}
 
 	return clk;
 }
@@ -370,7 +350,6 @@ at91_clk_register_main_rc_osc(struct regmap *regmap,
 static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
 {
 	struct clk *clk;
-	unsigned int irq;
 	u32 frequency = 0;
 	u32 accuracy = 0;
 	const char *name = np->name;
@@ -380,16 +359,11 @@ static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
 	of_property_read_u32(np, "clock-frequency", &frequency);
 	of_property_read_u32(np, "clock-accuracy", &accuracy);
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
 	regmap = syscon_node_to_regmap(of_get_parent(np));
 	if (IS_ERR(regmap))
 		return;
 
-	clk = at91_clk_register_main_rc_osc(regmap, irq, name, frequency,
-					    accuracy);
+	clk = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
 	if (IS_ERR(clk))
 		return;
 
@@ -536,9 +510,13 @@ static int clk_sam9x5_main_prepare(struct clk_hw *hw)
 	struct regmap *regmap = clkmain->base.regmap;
 
 	while (!clk_sam9x5_main_ready(regmap)) {
-		enable_irq(clkmain->base.irq);
-		wait_event(clkmain->base.wait,
-			   clk_sam9x5_main_ready(regmap));
+		if (clkmain->base.irq) {
+			enable_irq(clkmain->base.irq);
+			wait_event(clkmain->base.wait,
+				   clk_sam9x5_main_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return clk_main_probe_frequency(regmap);
@@ -577,9 +555,13 @@ static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
 		regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
 
 	while (!clk_sam9x5_main_ready(regmap)) {
-		enable_irq(clkmain->base.irq);
-		wait_event(clkmain->base.wait,
-			   clk_sam9x5_main_ready(regmap));
+		if (clkmain->base.irq) {
+			enable_irq(clkmain->base.irq);
+			wait_event(clkmain->base.wait,
+				   clk_sam9x5_main_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -605,12 +587,10 @@ static const struct clk_ops sam9x5_main_ops = {
 
 static struct clk * __init
 at91_clk_register_sam9x5_main(struct regmap *regmap,
-			      unsigned int irq,
 			      const char *name,
 			      const char **parent_names,
 			      int num_parents)
 {
-	int ret;
 	struct clk_sam9x5_main *clkmain;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -634,21 +614,12 @@ at91_clk_register_sam9x5_main(struct regmap *regmap,
 
 	clkmain->base.hw.init = &init;
 	clkmain->base.regmap = regmap;
-	clkmain->base.irq = irq;
 	regmap_read(clkmain->base.regmap, AT91_CKGR_MOR, &status);
 	clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
-	init_waitqueue_head(&clkmain->base.wait);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = request_irq(irq, clk_main_irq_handler,
-			  IRQF_TRIGGER_HIGH, name, &clkmain->base);
-	if (ret)
-		return ERR_PTR(ret);
 
 	clk = clk_register(NULL, &clkmain->base.hw);
-	if (IS_ERR(clk)) {
-		free_irq(irq, clkmain);
+	if (IS_ERR(clk))
 		kfree(clkmain);
-	}
 
 	return clk;
 }
@@ -658,7 +629,6 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
 	struct clk *clk;
 	const char *parent_names[2];
 	int num_parents;
-	unsigned int irq;
 	const char *name = np->name;
 	struct regmap *regmap;
 
@@ -673,11 +643,7 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
 
 	of_property_read_string(np, "clock-output-names", &name);
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
-	clk = at91_clk_register_sam9x5_main(regmap, irq, name, parent_names,
+	clk = at91_clk_register_sam9x5_main(regmap, name, parent_names,
 					    num_parents);
 	if (IS_ERR(clk))
 		return;
@@ -686,3 +652,45 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
 	       of_at91sam9x5_clk_main_setup);
+
+static const struct of_device_id atmel_clk_main_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-main-osc" },
+	{ .compatible = "atmel,at91sam9x5-clk-main-rc-osc" },
+	{ .compatible = "atmel,at91sam9x5-clk-main" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_main_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_main *clkmain;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	clkmain = to_clk_main(hw);
+	clkmain->irq = platform_get_irq(pdev, 0);
+	if (!clkmain->irq)
+		return 0;
+
+	init_waitqueue_head(&clkmain->wait);
+	irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, clkmain->irq, clk_main_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk),
+			       clkmain);
+	if (ret)
+		clkmain->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_main = {
+	.driver = {
+		.name = "atmel-clk-main",
+		.of_match_table = atmel_clk_main_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_main, atmel_clk_main_probe);
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index 8d94ddfc9c72..700d0cbf5cd4 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -8,12 +8,15 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
@@ -77,9 +80,13 @@ static int clk_master_prepare(struct clk_hw *hw)
 	struct clk_master *master = to_clk_master(hw);
 
 	while (!clk_master_ready(master->regmap)) {
-		enable_irq(master->irq);
-		wait_event(master->wait,
-			   clk_master_ready(master->regmap));
+		if (master->irq) {
+			enable_irq(master->irq);
+			wait_event(master->wait,
+				   clk_master_ready(master->regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -143,13 +150,12 @@ static const struct clk_ops master_ops = {
 };
 
 static struct clk * __init
-at91_clk_register_master(struct regmap *regmap, unsigned int irq,
+at91_clk_register_master(struct regmap *regmap,
 		const char *name, int num_parents,
 		const char **parent_names,
 		const struct clk_master_layout *layout,
 		const struct clk_master_characteristics *characteristics)
 {
-	int ret;
 	struct clk_master *master;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -171,19 +177,9 @@ at91_clk_register_master(struct regmap *regmap, unsigned int irq,
 	master->layout = layout;
 	master->characteristics = characteristics;
 	master->regmap = regmap;
-	master->irq = irq;
-	init_waitqueue_head(&master->wait);
-	irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
-	ret = request_irq(master->irq, clk_master_irq_handler,
-			  IRQF_TRIGGER_HIGH, "clk-master", master);
-	if (ret) {
-		kfree(master);
-		return ERR_PTR(ret);
-	}
 
 	clk = clk_register(NULL, &master->hw);
 	if (IS_ERR(clk)) {
-		free_irq(master->irq, master);
 		kfree(master);
 	}
 
@@ -233,7 +229,6 @@ of_at91_clk_master_setup(struct device_node *np,
 {
 	struct clk *clk;
 	int num_parents;
-	unsigned int irq;
 	const char *parent_names[MASTER_SOURCE_MAX];
 	const char *name = np->name;
 	struct clk_master_characteristics *characteristics;
@@ -255,11 +250,7 @@ of_at91_clk_master_setup(struct device_node *np,
 	if (IS_ERR(regmap))
 		return;
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		goto out_free_characteristics;
-
-	clk = at91_clk_register_master(regmap, irq, name, num_parents,
+	clk = at91_clk_register_master(regmap, name, num_parents,
 				       parent_names, layout,
 				       characteristics);
 	if (IS_ERR(clk))
@@ -285,3 +276,44 @@ static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
 	       of_at91sam9x5_clk_master_setup);
+
+static const struct of_device_id atmel_clk_master_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-master" },
+	{ .compatible = "atmel,at91sam9x5-clk-master" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_master_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_master *master;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	master = to_clk_master(hw);
+	master->irq = platform_get_irq(pdev, 0);
+	if (!master->irq)
+		return 0;
+
+	init_waitqueue_head(&master->wait);
+	irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, master->irq, clk_master_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk),
+			       master);
+	if (ret)
+		master->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_master = {
+	.driver = {
+		.name = "atmel-clk-master",
+		.of_match_table = atmel_clk_master_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_master, atmel_clk_master_probe);
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
index 5f4c6ce628e0..0cf69865c2c8 100644
--- a/drivers/clk/at91/clk-pll.c
+++ b/drivers/clk/at91/clk-pll.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -21,6 +22,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include "pmc.h"
@@ -128,9 +131,13 @@ static int clk_pll_prepare(struct clk_hw *hw)
 			((pll->mul & layout->mul_mask) << layout->mul_shift));
 
 	while (!clk_pll_ready(regmap, pll->id)) {
-		enable_irq(pll->irq);
-		wait_event(pll->wait,
-			   clk_pll_ready(regmap, pll->id));
+		if (pll->irq) {
+			enable_irq(pll->irq);
+			wait_event(pll->wait,
+				   clk_pll_ready(regmap, pll->id));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -320,7 +327,7 @@ static const struct clk_ops pll_ops = {
 };
 
 static struct clk * __init
-at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
+at91_clk_register_pll(struct regmap *regmap, const char *name,
 		      const char *parent_name, u8 id,
 		      const struct clk_pll_layout *layout,
 		      const struct clk_pll_characteristics *characteristics)
@@ -328,7 +335,6 @@ at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
 	struct clk_pll *pll;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
-	int ret;
 	int offset = PLL_REG(id);
 	unsigned int pllr;
 
@@ -350,22 +356,12 @@ at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
 	pll->layout = layout;
 	pll->characteristics = characteristics;
 	pll->regmap = regmap;
-	pll->irq = irq;
 	regmap_read(regmap, offset, &pllr);
 	pll->div = PLL_DIV(pllr);
 	pll->mul = PLL_MUL(pllr, layout);
-	init_waitqueue_head(&pll->wait);
-	irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
-	ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
-			  id ? "clk-pllb" : "clk-plla", pll);
-	if (ret) {
-		kfree(pll);
-		return ERR_PTR(ret);
-	}
 
 	clk = clk_register(NULL, &pll->hw);
 	if (IS_ERR(clk)) {
-		free_irq(pll->irq, pll);
 		kfree(pll);
 	}
 
@@ -499,7 +495,6 @@ of_at91_clk_pll_setup(struct device_node *np,
 		      const struct clk_pll_layout *layout)
 {
 	u32 id;
-	unsigned int irq;
 	struct clk *clk;
 	struct regmap *regmap;
 	const char *parent_name;
@@ -521,11 +516,7 @@ of_at91_clk_pll_setup(struct device_node *np,
 	if (!characteristics)
 		return;
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
-	clk = at91_clk_register_pll(regmap, irq, name, parent_name, id, layout,
+	clk = at91_clk_register_pll(regmap, name, parent_name, id, layout,
 				    characteristics);
 	if (IS_ERR(clk))
 		goto out_free_characteristics;
@@ -564,3 +555,45 @@ static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
 	       of_sama5d3_clk_pll_setup);
+
+static const struct of_device_id atmel_clk_pll_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-pll" },
+	{ .compatible = "atmel,at91sam9g45-clk-pll" },
+	{ .compatible = "atmel,at91sam9g20-clk-pllb" },
+	{ .compatible = "atmel,sama5d3-clk-pll" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_pll_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_pll *pll;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	pll = to_clk_pll(hw);
+	pll->irq = platform_get_irq(pdev, 0);
+	if (!pll->irq)
+		return 0;
+
+	init_waitqueue_head(&pll->wait);
+	irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, pll->irq, clk_pll_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk), pll);
+	if (ret)
+		pll->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_pll = {
+	.driver = {
+		.name = "atmel-clk-pll",
+		.of_match_table = atmel_clk_pll_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_pll, atmel_clk_pll_probe);
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 0593adf1bf4b..d5fc7bbcc6b3 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -20,6 +21,8 @@
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include "pmc.h"
@@ -41,6 +44,7 @@ static inline int is_pck(int id)
 {
 	return (id >= 8) && (id <= 15);
 }
+
 static irqreturn_t clk_system_irq_handler(int irq, void *dev_id)
 {
 	struct clk_system *sys = (struct clk_system *)dev_id;
@@ -114,12 +118,11 @@ static const struct clk_ops system_ops = {
 
 static struct clk * __init
 at91_clk_register_system(struct regmap *regmap, const char *name,
-			 const char *parent_name, u8 id, int irq)
+			 const char *parent_name, u8 id)
 {
 	struct clk_system *sys;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
-	int ret;
 
 	if (!parent_name || id > SYSTEM_MAX_ID)
 		return ERR_PTR(-EINVAL);
@@ -137,24 +140,10 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
 	sys->id = id;
 	sys->hw.init = &init;
 	sys->regmap = regmap;
-	sys->irq = irq;
-	if (irq) {
-		init_waitqueue_head(&sys->wait);
-		irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
-		ret = request_irq(sys->irq, clk_system_irq_handler,
-				IRQF_TRIGGER_HIGH, name, sys);
-		if (ret) {
-			kfree(sys);
-			return ERR_PTR(ret);
-		}
-	}
 
 	clk = clk_register(NULL, &sys->hw);
-	if (IS_ERR(clk)) {
-		if (irq)
-			free_irq(sys->irq, sys);
+	if (IS_ERR(clk))
 		kfree(sys);
-	}
 
 	return clk;
 }
@@ -162,7 +151,6 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
 static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
 {
 	int num;
-	int irq = 0;
 	u32 id;
 	struct clk *clk;
 	const char *name;
@@ -185,13 +173,9 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
 		if (of_property_read_string(np, "clock-output-names", &name))
 			name = sysclknp->name;
 
-		if (is_pck(id))
-			irq = irq_of_parse_and_map(sysclknp, 0);
-
 		parent_name = of_clk_get_parent_name(sysclknp, 0);
 
-		clk = at91_clk_register_system(regmap, name, parent_name, id,
-					       irq);
+		clk = at91_clk_register_system(regmap, name, parent_name, id);
 		if (IS_ERR(clk))
 			continue;
 
@@ -200,3 +184,52 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
 	       of_at91rm9200_clk_sys_setup);
+
+static const struct of_device_id atmel_clk_sys_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-system" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_sys_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *sysclknp;
+
+	for_each_child_of_node(np, sysclknp) {
+		struct of_phandle_args clkspec = { .np = sysclknp};
+		struct clk_hw *hw;
+		struct clk_system *sys;
+		int err;
+
+		hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+		if (!hw)
+			continue;
+
+		sys = to_clk_system(hw);
+		if (!is_pck(sys->id))
+			continue;
+
+		sys->irq = irq_of_parse_and_map(sysclknp, 0);
+		if (!sys->irq)
+			continue;
+
+		init_waitqueue_head(&sys->wait);
+		irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
+		err = devm_request_irq(&pdev->dev, sys->irq,
+				       clk_system_irq_handler,
+				       IRQF_TRIGGER_HIGH,
+				       __clk_get_name(hw->clk), sys);
+		if (err)
+			sys->irq = 0;
+	}
+
+	return 0;
+}
+
+static struct platform_driver atmel_clk_sys = {
+	.driver = {
+		.name = "atmel-clk-sys",
+		.of_match_table = atmel_clk_sys_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_sys, atmel_clk_sys_probe);
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
index 58a310e5768c..1f2fbf3bd13e 100644
--- a/drivers/clk/at91/clk-utmi.c
+++ b/drivers/clk/at91/clk-utmi.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -20,6 +21,8 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include "pmc.h"
@@ -63,9 +66,13 @@ static int clk_utmi_prepare(struct clk_hw *hw)
 	regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr);
 
 	while (!clk_utmi_ready(utmi->regmap)) {
-		enable_irq(utmi->irq);
-		wait_event(utmi->wait,
-			   clk_utmi_ready(utmi->regmap));
+		if (utmi->irq) {
+			enable_irq(utmi->irq);
+			wait_event(utmi->wait,
+				   clk_utmi_ready(utmi->regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -100,10 +107,9 @@ static const struct clk_ops utmi_ops = {
 };
 
 static struct clk * __init
-at91_clk_register_utmi(struct regmap *regmap, unsigned int irq,
+at91_clk_register_utmi(struct regmap *regmap,
 		       const char *name, const char *parent_name)
 {
-	int ret;
 	struct clk_utmi *utmi;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -120,28 +126,16 @@ at91_clk_register_utmi(struct regmap *regmap, unsigned int irq,
 
 	utmi->hw.init = &init;
 	utmi->regmap = regmap;
-	utmi->irq = irq;
-	init_waitqueue_head(&utmi->wait);
-	irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
-	ret = request_irq(utmi->irq, clk_utmi_irq_handler,
-			  IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
-	if (ret) {
-		kfree(utmi);
-		return ERR_PTR(ret);
-	}
 
 	clk = clk_register(NULL, &utmi->hw);
-	if (IS_ERR(clk)) {
-		free_irq(utmi->irq, utmi);
+	if (IS_ERR(clk))
 		kfree(utmi);
-	}
 
 	return clk;
 }
 
 static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
 {
-	unsigned int irq;
 	struct clk *clk;
 	const char *parent_name;
 	const char *name = np->name;
@@ -151,15 +145,11 @@ static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
 
 	of_property_read_string(np, "clock-output-names", &name);
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
 	regmap = syscon_node_to_regmap(of_get_parent(np));
 	if (IS_ERR(regmap))
 		return;
 
-	clk = at91_clk_register_utmi(regmap, irq, name, parent_name);
+	clk = at91_clk_register_utmi(regmap, name, parent_name);
 	if (IS_ERR(clk))
 		return;
 
@@ -168,3 +158,42 @@ static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
 	       of_at91sam9x5_clk_utmi_setup);
+
+static const struct of_device_id atmel_clk_utmi_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9x5-clk-utmi" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_utmi_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_utmi *utmi;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	utmi = to_clk_utmi(hw);
+	utmi->irq = platform_get_irq(pdev, 0);
+	if (!utmi->irq)
+		return 0;
+
+	init_waitqueue_head(&utmi->wait);
+	irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, utmi->irq, clk_utmi_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk), utmi);
+	if (ret)
+		utmi->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_utmi = {
+	.driver = {
+		.name = "atmel-clk-utmi",
+		.of_match_table = atmel_clk_utmi_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_utmi, atmel_clk_utmi_probe);
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index a1cc7afc5885..6c1f08a73373 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -20,6 +20,9 @@
 #include <linux/irqdomain.h>
 #include <linux/of_irq.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include <asm/proc-fns.h>
@@ -240,32 +243,29 @@ static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
 	pmc->virq = virq;
 	pmc->caps = caps;
 
-	pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc);
-	if (!pmc->irqdomain)
-		goto out_free_pmc;
-
-	regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff);
-	if (request_irq(pmc->virq, pmc_irq_handler,
-			IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
-		goto out_remove_irqdomain;
-
 	return pmc;
-
-out_remove_irqdomain:
-	irq_domain_remove(pmc->irqdomain);
-out_free_pmc:
-	kfree(pmc);
-
-	return NULL;
 }
 
-static void __init of_at91_pmc_setup(struct device_node *np,
-				     const struct at91_pmc_caps *caps)
+static const struct of_device_id atmel_pmc_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-pmc", .data = &at91rm9200_caps },
+	{ .compatible = "atmel,at91sam9260-pmc", .data = &at91sam9260_caps },
+	{ .compatible = "atmel,at91sam9g45-pmc", .data = &at91sam9g45_caps },
+	{ .compatible = "atmel,at91sam9n12-pmc", .data = &at91sam9n12_caps },
+	{ .compatible = "atmel,at91sam9x5-pmc", .data = &at91sam9x5_caps },
+	{ .compatible = "atmel,sama5d3-pmc", .data = &sama5d3_caps },
+	{ /* sentinel */ },
+};
+
+static int __init atmel_pmc_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *of_id;
+	const struct at91_pmc_caps *caps;
+	struct device_node *np = pdev->dev.of_node;
 	struct at91_pmc *pmc;
 	void __iomem *regbase = of_iomap(np, 0);
 	struct regmap *regmap;
 	int virq;
+	int ret = 0;
 
 	regmap = syscon_node_to_regmap(np);
 	if (IS_ERR(regmap))
@@ -273,51 +273,35 @@ static void __init of_at91_pmc_setup(struct device_node *np,
 
 	virq = irq_of_parse_and_map(np, 0);
 	if (!virq)
-		return;
+		return 0;
+
+	of_id = of_match_device(atmel_pmc_dt_ids, &pdev->dev);
+	caps = of_id->data;
 
 	pmc = at91_pmc_init(np, regmap, regbase, virq, caps);
 	if (!pmc)
-		return;
-}
+		return 0;
 
-static void __init of_at91rm9200_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91rm9200_caps);
-}
-CLK_OF_DECLARE(at91rm9200_clk_pmc, "atmel,at91rm9200-pmc",
-	       of_at91rm9200_pmc_setup);
-
-static void __init of_at91sam9260_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9260_caps);
-}
-CLK_OF_DECLARE(at91sam9260_clk_pmc, "atmel,at91sam9260-pmc",
-	       of_at91sam9260_pmc_setup);
+	pmc->irqdomain = irq_domain_add_linear(pdev->dev.of_node, 32,
+					       &pmc_irq_ops, pmc);
+	if (!pmc->irqdomain)
+		return 0;
 
-static void __init of_at91sam9g45_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9g45_caps);
-}
-CLK_OF_DECLARE(at91sam9g45_clk_pmc, "atmel,at91sam9g45-pmc",
-	       of_at91sam9g45_pmc_setup);
+	regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff);
+	ret = request_irq(pmc->virq, pmc_irq_handler,
+			  IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc);
+	if (ret)
+		return ret;
 
-static void __init of_at91sam9n12_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9n12_caps);
-}
-CLK_OF_DECLARE(at91sam9n12_clk_pmc, "atmel,at91sam9n12-pmc",
-	       of_at91sam9n12_pmc_setup);
+	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 
-static void __init of_at91sam9x5_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9x5_caps);
+	return 0;
 }
-CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc",
-	       of_at91sam9x5_pmc_setup);
 
-static void __init of_sama5d3_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &sama5d3_caps);
-}
-CLK_OF_DECLARE(sama5d3_clk_pmc, "atmel,sama5d3-pmc",
-	       of_sama5d3_pmc_setup);
+static struct platform_driver atmel_pmc = {
+	.driver = {
+		.name = "atmel-pmc",
+		.of_match_table = atmel_pmc_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_pmc, atmel_pmc_probe);
-- 
2.1.4


WARNING: multiple messages have this Message-ID (diff)
From: alexandre.belloni@free-electrons.com (Alexandre Belloni)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 05/14] clk: at91: make IRQ optional and register them later
Date: Mon, 12 Oct 2015 16:28:42 +0200	[thread overview]
Message-ID: <1444660131-14954-6-git-send-email-alexandre.belloni@free-electrons.com> (raw)
In-Reply-To: <1444660131-14954-1-git-send-email-alexandre.belloni@free-electrons.com>

The AT91 clock drivers make use of IRQs to avoid polling when waiting for
some clocks to be enabled. Unfortunately, this leads to a crash when those
IRQs are threaded (which happens when using preempt-rt) because they are
registered before thread creation is possible.

Use polling on those clocks until the IRQ is registered and register the
IRQ at module probe time.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 drivers/clk/at91/clk-main.c   | 152 ++++++++++++++++++++++--------------------
 drivers/clk/at91/clk-master.c |  74 ++++++++++++++------
 drivers/clk/at91/clk-pll.c    |  75 +++++++++++++++------
 drivers/clk/at91/clk-system.c |  79 +++++++++++++++-------
 drivers/clk/at91/clk-utmi.c   |  75 ++++++++++++++-------
 drivers/clk/at91/pmc.c        |  98 ++++++++++++---------------
 6 files changed, 336 insertions(+), 217 deletions(-)

diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 5841eb958f83..4b021714e801 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -22,6 +23,8 @@
 #include <linux/regmap.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include "pmc.h"
 
@@ -110,9 +113,13 @@ static int clk_main_osc_prepare(struct clk_hw *hw)
 	}
 
 	while (!clk_main_osc_ready(regmap)) {
-		enable_irq(osc->base.irq);
-		wait_event(osc->base.wait,
-			   clk_main_osc_ready(regmap));
+		if (osc->base.irq) {
+			enable_irq(osc->base.irq);
+			wait_event(osc->base.wait,
+				   clk_main_osc_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -158,17 +165,15 @@ static const struct clk_ops main_osc_ops = {
 
 static struct clk * __init
 at91_clk_register_main_osc(struct regmap *regmap,
-			   unsigned int irq,
 			   const char *name,
 			   const char *parent_name,
 			   bool bypass)
 {
-	int ret;
 	struct clk_main_osc *osc;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
 
-	if (!irq || !name || !parent_name)
+	if (!name || !parent_name)
 		return ERR_PTR(-EINVAL);
 
 	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
@@ -183,16 +188,6 @@ at91_clk_register_main_osc(struct regmap *regmap,
 
 	osc->base.hw.init = &init;
 	osc->base.regmap = regmap;
-	osc->base.irq = irq;
-
-	init_waitqueue_head(&osc->base.wait);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = request_irq(irq, clk_main_irq_handler,
-			  IRQF_TRIGGER_HIGH, name, &osc->base);
-	if (ret) {
-		kfree(osc);
-		return ERR_PTR(ret);
-	}
 
 	if (bypass)
 		regmap_update_bits(regmap,
@@ -201,10 +196,8 @@ at91_clk_register_main_osc(struct regmap *regmap,
 				   AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
 
 	clk = clk_register(NULL, &osc->base.hw);
-	if (IS_ERR(clk)) {
-		free_irq(irq, osc);
+	if (IS_ERR(clk))
 		kfree(osc);
-	}
 
 	return clk;
 }
@@ -212,7 +205,6 @@ at91_clk_register_main_osc(struct regmap *regmap,
 static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
 {
 	struct clk *clk;
-	unsigned int irq;
 	const char *name = np->name;
 	const char *parent_name;
 	struct regmap *regmap;
@@ -226,11 +218,7 @@ static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
 	if (IS_ERR(regmap))
 		return;
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
-	clk = at91_clk_register_main_osc(regmap, irq, name, parent_name, bypass);
+	clk = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
 	if (IS_ERR(clk))
 		return;
 
@@ -262,9 +250,13 @@ static int clk_main_rc_osc_prepare(struct clk_hw *hw)
 				   AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
 
 	while (!clk_main_rc_osc_ready(regmap)) {
-		enable_irq(osc->base.irq);
-		wait_event(osc->base.wait,
-			   clk_main_rc_osc_ready(regmap));
+		if (osc->base.irq) {
+			enable_irq(osc->base.irq);
+			wait_event(osc->base.wait,
+				   clk_main_rc_osc_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -323,11 +315,9 @@ static const struct clk_ops main_rc_osc_ops = {
 
 static struct clk * __init
 at91_clk_register_main_rc_osc(struct regmap *regmap,
-			      unsigned int irq,
 			      const char *name,
 			      u32 frequency, u32 accuracy)
 {
-	int ret;
 	struct clk_main_rc_osc *osc;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -347,22 +337,12 @@ at91_clk_register_main_rc_osc(struct regmap *regmap,
 
 	osc->base.hw.init = &init;
 	osc->base.regmap = regmap;
-	osc->base.irq = irq;
 	osc->frequency = frequency;
 	osc->accuracy = accuracy;
 
-	init_waitqueue_head(&osc->base.wait);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = request_irq(irq, clk_main_irq_handler,
-			  IRQF_TRIGGER_HIGH, name, &osc->base);
-	if (ret)
-		return ERR_PTR(ret);
-
 	clk = clk_register(NULL, &osc->base.hw);
-	if (IS_ERR(clk)) {
-		free_irq(irq, osc);
+	if (IS_ERR(clk))
 		kfree(osc);
-	}
 
 	return clk;
 }
@@ -370,7 +350,6 @@ at91_clk_register_main_rc_osc(struct regmap *regmap,
 static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
 {
 	struct clk *clk;
-	unsigned int irq;
 	u32 frequency = 0;
 	u32 accuracy = 0;
 	const char *name = np->name;
@@ -380,16 +359,11 @@ static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
 	of_property_read_u32(np, "clock-frequency", &frequency);
 	of_property_read_u32(np, "clock-accuracy", &accuracy);
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
 	regmap = syscon_node_to_regmap(of_get_parent(np));
 	if (IS_ERR(regmap))
 		return;
 
-	clk = at91_clk_register_main_rc_osc(regmap, irq, name, frequency,
-					    accuracy);
+	clk = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
 	if (IS_ERR(clk))
 		return;
 
@@ -536,9 +510,13 @@ static int clk_sam9x5_main_prepare(struct clk_hw *hw)
 	struct regmap *regmap = clkmain->base.regmap;
 
 	while (!clk_sam9x5_main_ready(regmap)) {
-		enable_irq(clkmain->base.irq);
-		wait_event(clkmain->base.wait,
-			   clk_sam9x5_main_ready(regmap));
+		if (clkmain->base.irq) {
+			enable_irq(clkmain->base.irq);
+			wait_event(clkmain->base.wait,
+				   clk_sam9x5_main_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return clk_main_probe_frequency(regmap);
@@ -577,9 +555,13 @@ static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
 		regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
 
 	while (!clk_sam9x5_main_ready(regmap)) {
-		enable_irq(clkmain->base.irq);
-		wait_event(clkmain->base.wait,
-			   clk_sam9x5_main_ready(regmap));
+		if (clkmain->base.irq) {
+			enable_irq(clkmain->base.irq);
+			wait_event(clkmain->base.wait,
+				   clk_sam9x5_main_ready(regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -605,12 +587,10 @@ static const struct clk_ops sam9x5_main_ops = {
 
 static struct clk * __init
 at91_clk_register_sam9x5_main(struct regmap *regmap,
-			      unsigned int irq,
 			      const char *name,
 			      const char **parent_names,
 			      int num_parents)
 {
-	int ret;
 	struct clk_sam9x5_main *clkmain;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -634,21 +614,12 @@ at91_clk_register_sam9x5_main(struct regmap *regmap,
 
 	clkmain->base.hw.init = &init;
 	clkmain->base.regmap = regmap;
-	clkmain->base.irq = irq;
 	regmap_read(clkmain->base.regmap, AT91_CKGR_MOR, &status);
 	clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
-	init_waitqueue_head(&clkmain->base.wait);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
-	ret = request_irq(irq, clk_main_irq_handler,
-			  IRQF_TRIGGER_HIGH, name, &clkmain->base);
-	if (ret)
-		return ERR_PTR(ret);
 
 	clk = clk_register(NULL, &clkmain->base.hw);
-	if (IS_ERR(clk)) {
-		free_irq(irq, clkmain);
+	if (IS_ERR(clk))
 		kfree(clkmain);
-	}
 
 	return clk;
 }
@@ -658,7 +629,6 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
 	struct clk *clk;
 	const char *parent_names[2];
 	int num_parents;
-	unsigned int irq;
 	const char *name = np->name;
 	struct regmap *regmap;
 
@@ -673,11 +643,7 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
 
 	of_property_read_string(np, "clock-output-names", &name);
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
-	clk = at91_clk_register_sam9x5_main(regmap, irq, name, parent_names,
+	clk = at91_clk_register_sam9x5_main(regmap, name, parent_names,
 					    num_parents);
 	if (IS_ERR(clk))
 		return;
@@ -686,3 +652,45 @@ static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
 	       of_at91sam9x5_clk_main_setup);
+
+static const struct of_device_id atmel_clk_main_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-main-osc" },
+	{ .compatible = "atmel,at91sam9x5-clk-main-rc-osc" },
+	{ .compatible = "atmel,at91sam9x5-clk-main" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_main_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_main *clkmain;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	clkmain = to_clk_main(hw);
+	clkmain->irq = platform_get_irq(pdev, 0);
+	if (!clkmain->irq)
+		return 0;
+
+	init_waitqueue_head(&clkmain->wait);
+	irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, clkmain->irq, clk_main_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk),
+			       clkmain);
+	if (ret)
+		clkmain->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_main = {
+	.driver = {
+		.name = "atmel-clk-main",
+		.of_match_table = atmel_clk_main_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_main, atmel_clk_main_probe);
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index 8d94ddfc9c72..700d0cbf5cd4 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -8,12 +8,15 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
@@ -77,9 +80,13 @@ static int clk_master_prepare(struct clk_hw *hw)
 	struct clk_master *master = to_clk_master(hw);
 
 	while (!clk_master_ready(master->regmap)) {
-		enable_irq(master->irq);
-		wait_event(master->wait,
-			   clk_master_ready(master->regmap));
+		if (master->irq) {
+			enable_irq(master->irq);
+			wait_event(master->wait,
+				   clk_master_ready(master->regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -143,13 +150,12 @@ static const struct clk_ops master_ops = {
 };
 
 static struct clk * __init
-at91_clk_register_master(struct regmap *regmap, unsigned int irq,
+at91_clk_register_master(struct regmap *regmap,
 		const char *name, int num_parents,
 		const char **parent_names,
 		const struct clk_master_layout *layout,
 		const struct clk_master_characteristics *characteristics)
 {
-	int ret;
 	struct clk_master *master;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -171,19 +177,9 @@ at91_clk_register_master(struct regmap *regmap, unsigned int irq,
 	master->layout = layout;
 	master->characteristics = characteristics;
 	master->regmap = regmap;
-	master->irq = irq;
-	init_waitqueue_head(&master->wait);
-	irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
-	ret = request_irq(master->irq, clk_master_irq_handler,
-			  IRQF_TRIGGER_HIGH, "clk-master", master);
-	if (ret) {
-		kfree(master);
-		return ERR_PTR(ret);
-	}
 
 	clk = clk_register(NULL, &master->hw);
 	if (IS_ERR(clk)) {
-		free_irq(master->irq, master);
 		kfree(master);
 	}
 
@@ -233,7 +229,6 @@ of_at91_clk_master_setup(struct device_node *np,
 {
 	struct clk *clk;
 	int num_parents;
-	unsigned int irq;
 	const char *parent_names[MASTER_SOURCE_MAX];
 	const char *name = np->name;
 	struct clk_master_characteristics *characteristics;
@@ -255,11 +250,7 @@ of_at91_clk_master_setup(struct device_node *np,
 	if (IS_ERR(regmap))
 		return;
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		goto out_free_characteristics;
-
-	clk = at91_clk_register_master(regmap, irq, name, num_parents,
+	clk = at91_clk_register_master(regmap, name, num_parents,
 				       parent_names, layout,
 				       characteristics);
 	if (IS_ERR(clk))
@@ -285,3 +276,44 @@ static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
 	       of_at91sam9x5_clk_master_setup);
+
+static const struct of_device_id atmel_clk_master_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-master" },
+	{ .compatible = "atmel,at91sam9x5-clk-master" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_master_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_master *master;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	master = to_clk_master(hw);
+	master->irq = platform_get_irq(pdev, 0);
+	if (!master->irq)
+		return 0;
+
+	init_waitqueue_head(&master->wait);
+	irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, master->irq, clk_master_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk),
+			       master);
+	if (ret)
+		master->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_master = {
+	.driver = {
+		.name = "atmel-clk-master",
+		.of_match_table = atmel_clk_master_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_master, atmel_clk_master_probe);
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
index 5f4c6ce628e0..0cf69865c2c8 100644
--- a/drivers/clk/at91/clk-pll.c
+++ b/drivers/clk/at91/clk-pll.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -21,6 +22,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include "pmc.h"
@@ -128,9 +131,13 @@ static int clk_pll_prepare(struct clk_hw *hw)
 			((pll->mul & layout->mul_mask) << layout->mul_shift));
 
 	while (!clk_pll_ready(regmap, pll->id)) {
-		enable_irq(pll->irq);
-		wait_event(pll->wait,
-			   clk_pll_ready(regmap, pll->id));
+		if (pll->irq) {
+			enable_irq(pll->irq);
+			wait_event(pll->wait,
+				   clk_pll_ready(regmap, pll->id));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -320,7 +327,7 @@ static const struct clk_ops pll_ops = {
 };
 
 static struct clk * __init
-at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
+at91_clk_register_pll(struct regmap *regmap, const char *name,
 		      const char *parent_name, u8 id,
 		      const struct clk_pll_layout *layout,
 		      const struct clk_pll_characteristics *characteristics)
@@ -328,7 +335,6 @@ at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
 	struct clk_pll *pll;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
-	int ret;
 	int offset = PLL_REG(id);
 	unsigned int pllr;
 
@@ -350,22 +356,12 @@ at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
 	pll->layout = layout;
 	pll->characteristics = characteristics;
 	pll->regmap = regmap;
-	pll->irq = irq;
 	regmap_read(regmap, offset, &pllr);
 	pll->div = PLL_DIV(pllr);
 	pll->mul = PLL_MUL(pllr, layout);
-	init_waitqueue_head(&pll->wait);
-	irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
-	ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
-			  id ? "clk-pllb" : "clk-plla", pll);
-	if (ret) {
-		kfree(pll);
-		return ERR_PTR(ret);
-	}
 
 	clk = clk_register(NULL, &pll->hw);
 	if (IS_ERR(clk)) {
-		free_irq(pll->irq, pll);
 		kfree(pll);
 	}
 
@@ -499,7 +495,6 @@ of_at91_clk_pll_setup(struct device_node *np,
 		      const struct clk_pll_layout *layout)
 {
 	u32 id;
-	unsigned int irq;
 	struct clk *clk;
 	struct regmap *regmap;
 	const char *parent_name;
@@ -521,11 +516,7 @@ of_at91_clk_pll_setup(struct device_node *np,
 	if (!characteristics)
 		return;
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
-	clk = at91_clk_register_pll(regmap, irq, name, parent_name, id, layout,
+	clk = at91_clk_register_pll(regmap, name, parent_name, id, layout,
 				    characteristics);
 	if (IS_ERR(clk))
 		goto out_free_characteristics;
@@ -564,3 +555,45 @@ static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
 	       of_sama5d3_clk_pll_setup);
+
+static const struct of_device_id atmel_clk_pll_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-pll" },
+	{ .compatible = "atmel,at91sam9g45-clk-pll" },
+	{ .compatible = "atmel,at91sam9g20-clk-pllb" },
+	{ .compatible = "atmel,sama5d3-clk-pll" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_pll_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_pll *pll;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	pll = to_clk_pll(hw);
+	pll->irq = platform_get_irq(pdev, 0);
+	if (!pll->irq)
+		return 0;
+
+	init_waitqueue_head(&pll->wait);
+	irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, pll->irq, clk_pll_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk), pll);
+	if (ret)
+		pll->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_pll = {
+	.driver = {
+		.name = "atmel-clk-pll",
+		.of_match_table = atmel_clk_pll_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_pll, atmel_clk_pll_probe);
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 0593adf1bf4b..d5fc7bbcc6b3 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -20,6 +21,8 @@
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include "pmc.h"
@@ -41,6 +44,7 @@ static inline int is_pck(int id)
 {
 	return (id >= 8) && (id <= 15);
 }
+
 static irqreturn_t clk_system_irq_handler(int irq, void *dev_id)
 {
 	struct clk_system *sys = (struct clk_system *)dev_id;
@@ -114,12 +118,11 @@ static const struct clk_ops system_ops = {
 
 static struct clk * __init
 at91_clk_register_system(struct regmap *regmap, const char *name,
-			 const char *parent_name, u8 id, int irq)
+			 const char *parent_name, u8 id)
 {
 	struct clk_system *sys;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
-	int ret;
 
 	if (!parent_name || id > SYSTEM_MAX_ID)
 		return ERR_PTR(-EINVAL);
@@ -137,24 +140,10 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
 	sys->id = id;
 	sys->hw.init = &init;
 	sys->regmap = regmap;
-	sys->irq = irq;
-	if (irq) {
-		init_waitqueue_head(&sys->wait);
-		irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
-		ret = request_irq(sys->irq, clk_system_irq_handler,
-				IRQF_TRIGGER_HIGH, name, sys);
-		if (ret) {
-			kfree(sys);
-			return ERR_PTR(ret);
-		}
-	}
 
 	clk = clk_register(NULL, &sys->hw);
-	if (IS_ERR(clk)) {
-		if (irq)
-			free_irq(sys->irq, sys);
+	if (IS_ERR(clk))
 		kfree(sys);
-	}
 
 	return clk;
 }
@@ -162,7 +151,6 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
 static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
 {
 	int num;
-	int irq = 0;
 	u32 id;
 	struct clk *clk;
 	const char *name;
@@ -185,13 +173,9 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
 		if (of_property_read_string(np, "clock-output-names", &name))
 			name = sysclknp->name;
 
-		if (is_pck(id))
-			irq = irq_of_parse_and_map(sysclknp, 0);
-
 		parent_name = of_clk_get_parent_name(sysclknp, 0);
 
-		clk = at91_clk_register_system(regmap, name, parent_name, id,
-					       irq);
+		clk = at91_clk_register_system(regmap, name, parent_name, id);
 		if (IS_ERR(clk))
 			continue;
 
@@ -200,3 +184,52 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
 	       of_at91rm9200_clk_sys_setup);
+
+static const struct of_device_id atmel_clk_sys_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-clk-system" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_sys_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *sysclknp;
+
+	for_each_child_of_node(np, sysclknp) {
+		struct of_phandle_args clkspec = { .np = sysclknp};
+		struct clk_hw *hw;
+		struct clk_system *sys;
+		int err;
+
+		hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+		if (!hw)
+			continue;
+
+		sys = to_clk_system(hw);
+		if (!is_pck(sys->id))
+			continue;
+
+		sys->irq = irq_of_parse_and_map(sysclknp, 0);
+		if (!sys->irq)
+			continue;
+
+		init_waitqueue_head(&sys->wait);
+		irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
+		err = devm_request_irq(&pdev->dev, sys->irq,
+				       clk_system_irq_handler,
+				       IRQF_TRIGGER_HIGH,
+				       __clk_get_name(hw->clk), sys);
+		if (err)
+			sys->irq = 0;
+	}
+
+	return 0;
+}
+
+static struct platform_driver atmel_clk_sys = {
+	.driver = {
+		.name = "atmel-clk-sys",
+		.of_match_table = atmel_clk_sys_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_sys, atmel_clk_sys_probe);
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
index 58a310e5768c..1f2fbf3bd13e 100644
--- a/drivers/clk/at91/clk-utmi.c
+++ b/drivers/clk/at91/clk-utmi.c
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
@@ -20,6 +21,8 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include "pmc.h"
@@ -63,9 +66,13 @@ static int clk_utmi_prepare(struct clk_hw *hw)
 	regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr);
 
 	while (!clk_utmi_ready(utmi->regmap)) {
-		enable_irq(utmi->irq);
-		wait_event(utmi->wait,
-			   clk_utmi_ready(utmi->regmap));
+		if (utmi->irq) {
+			enable_irq(utmi->irq);
+			wait_event(utmi->wait,
+				   clk_utmi_ready(utmi->regmap));
+		} else {
+			cpu_relax();
+		}
 	}
 
 	return 0;
@@ -100,10 +107,9 @@ static const struct clk_ops utmi_ops = {
 };
 
 static struct clk * __init
-at91_clk_register_utmi(struct regmap *regmap, unsigned int irq,
+at91_clk_register_utmi(struct regmap *regmap,
 		       const char *name, const char *parent_name)
 {
-	int ret;
 	struct clk_utmi *utmi;
 	struct clk *clk = NULL;
 	struct clk_init_data init;
@@ -120,28 +126,16 @@ at91_clk_register_utmi(struct regmap *regmap, unsigned int irq,
 
 	utmi->hw.init = &init;
 	utmi->regmap = regmap;
-	utmi->irq = irq;
-	init_waitqueue_head(&utmi->wait);
-	irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
-	ret = request_irq(utmi->irq, clk_utmi_irq_handler,
-			  IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
-	if (ret) {
-		kfree(utmi);
-		return ERR_PTR(ret);
-	}
 
 	clk = clk_register(NULL, &utmi->hw);
-	if (IS_ERR(clk)) {
-		free_irq(utmi->irq, utmi);
+	if (IS_ERR(clk))
 		kfree(utmi);
-	}
 
 	return clk;
 }
 
 static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
 {
-	unsigned int irq;
 	struct clk *clk;
 	const char *parent_name;
 	const char *name = np->name;
@@ -151,15 +145,11 @@ static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
 
 	of_property_read_string(np, "clock-output-names", &name);
 
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq)
-		return;
-
 	regmap = syscon_node_to_regmap(of_get_parent(np));
 	if (IS_ERR(regmap))
 		return;
 
-	clk = at91_clk_register_utmi(regmap, irq, name, parent_name);
+	clk = at91_clk_register_utmi(regmap, name, parent_name);
 	if (IS_ERR(clk))
 		return;
 
@@ -168,3 +158,42 @@ static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
 }
 CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
 	       of_at91sam9x5_clk_utmi_setup);
+
+static const struct of_device_id atmel_clk_utmi_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9x5-clk-utmi" },
+	{ /* sentinel */ }
+};
+
+static int __init atmel_clk_utmi_probe(struct platform_device *pdev)
+{
+	struct of_phandle_args clkspec = { .np = pdev->dev.of_node};
+	struct clk_utmi *utmi;
+	struct clk_hw *hw;
+	int ret;
+
+	hw = __clk_get_hw(of_clk_get_from_provider(&clkspec));
+	if (!hw)
+		return -ENODEV;
+
+	utmi = to_clk_utmi(hw);
+	utmi->irq = platform_get_irq(pdev, 0);
+	if (!utmi->irq)
+		return 0;
+
+	init_waitqueue_head(&utmi->wait);
+	irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
+	ret = devm_request_irq(&pdev->dev, utmi->irq, clk_utmi_irq_handler,
+			       IRQF_TRIGGER_HIGH, __clk_get_name(hw->clk), utmi);
+	if (ret)
+		utmi->irq = 0;
+
+	return ret;
+}
+
+static struct platform_driver atmel_clk_utmi = {
+	.driver = {
+		.name = "atmel-clk-utmi",
+		.of_match_table = atmel_clk_utmi_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_clk_utmi, atmel_clk_utmi_probe);
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index a1cc7afc5885..6c1f08a73373 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -20,6 +20,9 @@
 #include <linux/irqdomain.h>
 #include <linux/of_irq.h>
 #include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #include <asm/proc-fns.h>
@@ -240,32 +243,29 @@ static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
 	pmc->virq = virq;
 	pmc->caps = caps;
 
-	pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc);
-	if (!pmc->irqdomain)
-		goto out_free_pmc;
-
-	regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff);
-	if (request_irq(pmc->virq, pmc_irq_handler,
-			IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
-		goto out_remove_irqdomain;
-
 	return pmc;
-
-out_remove_irqdomain:
-	irq_domain_remove(pmc->irqdomain);
-out_free_pmc:
-	kfree(pmc);
-
-	return NULL;
 }
 
-static void __init of_at91_pmc_setup(struct device_node *np,
-				     const struct at91_pmc_caps *caps)
+static const struct of_device_id atmel_pmc_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-pmc", .data = &at91rm9200_caps },
+	{ .compatible = "atmel,at91sam9260-pmc", .data = &at91sam9260_caps },
+	{ .compatible = "atmel,at91sam9g45-pmc", .data = &at91sam9g45_caps },
+	{ .compatible = "atmel,at91sam9n12-pmc", .data = &at91sam9n12_caps },
+	{ .compatible = "atmel,at91sam9x5-pmc", .data = &at91sam9x5_caps },
+	{ .compatible = "atmel,sama5d3-pmc", .data = &sama5d3_caps },
+	{ /* sentinel */ },
+};
+
+static int __init atmel_pmc_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *of_id;
+	const struct at91_pmc_caps *caps;
+	struct device_node *np = pdev->dev.of_node;
 	struct at91_pmc *pmc;
 	void __iomem *regbase = of_iomap(np, 0);
 	struct regmap *regmap;
 	int virq;
+	int ret = 0;
 
 	regmap = syscon_node_to_regmap(np);
 	if (IS_ERR(regmap))
@@ -273,51 +273,35 @@ static void __init of_at91_pmc_setup(struct device_node *np,
 
 	virq = irq_of_parse_and_map(np, 0);
 	if (!virq)
-		return;
+		return 0;
+
+	of_id = of_match_device(atmel_pmc_dt_ids, &pdev->dev);
+	caps = of_id->data;
 
 	pmc = at91_pmc_init(np, regmap, regbase, virq, caps);
 	if (!pmc)
-		return;
-}
+		return 0;
 
-static void __init of_at91rm9200_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91rm9200_caps);
-}
-CLK_OF_DECLARE(at91rm9200_clk_pmc, "atmel,at91rm9200-pmc",
-	       of_at91rm9200_pmc_setup);
-
-static void __init of_at91sam9260_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9260_caps);
-}
-CLK_OF_DECLARE(at91sam9260_clk_pmc, "atmel,at91sam9260-pmc",
-	       of_at91sam9260_pmc_setup);
+	pmc->irqdomain = irq_domain_add_linear(pdev->dev.of_node, 32,
+					       &pmc_irq_ops, pmc);
+	if (!pmc->irqdomain)
+		return 0;
 
-static void __init of_at91sam9g45_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9g45_caps);
-}
-CLK_OF_DECLARE(at91sam9g45_clk_pmc, "atmel,at91sam9g45-pmc",
-	       of_at91sam9g45_pmc_setup);
+	regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff);
+	ret = request_irq(pmc->virq, pmc_irq_handler,
+			  IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc);
+	if (ret)
+		return ret;
 
-static void __init of_at91sam9n12_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9n12_caps);
-}
-CLK_OF_DECLARE(at91sam9n12_clk_pmc, "atmel,at91sam9n12-pmc",
-	       of_at91sam9n12_pmc_setup);
+	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 
-static void __init of_at91sam9x5_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &at91sam9x5_caps);
+	return 0;
 }
-CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc",
-	       of_at91sam9x5_pmc_setup);
 
-static void __init of_sama5d3_pmc_setup(struct device_node *np)
-{
-	of_at91_pmc_setup(np, &sama5d3_caps);
-}
-CLK_OF_DECLARE(sama5d3_clk_pmc, "atmel,sama5d3-pmc",
-	       of_sama5d3_pmc_setup);
+static struct platform_driver atmel_pmc = {
+	.driver = {
+		.name = "atmel-pmc",
+		.of_match_table = atmel_pmc_dt_ids,
+	},
+};
+module_platform_driver_probe(atmel_pmc, atmel_pmc_probe);
-- 
2.1.4

  parent reply	other threads:[~2015-10-12 14:29 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-12 14:28 [PATCH v2 00/14] ARM: at91: PMC driver rework Alexandre Belloni
2015-10-12 14:28 ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 01/14] ARM: at91/dt: use syscon for PMC Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 02/14] clk: at91: make use of syscon to share PMC registers in several drivers Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 03/14] clk: at91: make use of syscon/regmap internally Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-29  1:52   ` Yang, Wenyou
2015-10-29  1:52     ` Yang, Wenyou
2015-10-12 14:28 ` [PATCH v2 04/14] clk: at91: clk-main: factorize irq handling Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` Alexandre Belloni [this message]
2015-10-12 14:28   ` [PATCH v2 05/14] clk: at91: make IRQ optional and register them later Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 06/14] clk: at91: only disable available IRQs Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 07/14] clk: at91: pmc: merge at91_pmc_init in atmel_pmc_probe Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 08/14] clk: at91: pmc: move pmc structures to C file Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 09/14] ARM: at91: pm: simply call at91_pm_init Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 10/14] ARM: at91: pm: find and remap the pmc Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-29  1:50   ` Yang, Wenyou
2015-10-29  1:50     ` Yang, Wenyou
2015-10-12 14:28 ` [PATCH v2 11/14] ARM: at91: pm: move idle functions to pm.c Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 12/14] ARM: at91: remove useless includes and function prototypes Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 13/14] usb: gadget: atmel: access the PMC using regmap Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni
2015-10-12 14:28 ` [PATCH v2 14/14] clk: at91: pmc: drop at91_pmc_base Alexandre Belloni
2015-10-12 14:28   ` Alexandre Belloni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1444660131-14954-6-git-send-email-alexandre.belloni@free-electrons.com \
    --to=alexandre.belloni@free-electrons.com \
    --cc=boris.brezillon@free-electrons.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mturquette@baylibre.com \
    --cc=nicolas.ferre@atmel.com \
    --cc=plagnioj@jcrosoft.com \
    --cc=sboyd@codeaurora.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.