437fb9
From ba60a01e02086b0a242cf5ea3c59419108ada40b Mon Sep 17 00:00:00 2001
437fb9
From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
Date: Tue, 11 Jun 2019 19:58:34 +0200
437fb9
Subject: [PATCH 1/5] clk: bcm2835: remove pllb
437fb9
437fb9
Raspberry Pi's firmware controls this pll, we should use the firmware
437fb9
interface to access it.
437fb9
437fb9
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
Acked-by: Eric Anholt <eric@anholt.net>
437fb9
---
437fb9
 drivers/clk/bcm/clk-bcm2835.c | 28 ++++------------------------
437fb9
 1 file changed, 4 insertions(+), 24 deletions(-)
437fb9
437fb9
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
437fb9
index 770bb01f523e..867ae3c20041 100644
437fb9
--- a/drivers/clk/bcm/clk-bcm2835.c
437fb9
+++ b/drivers/clk/bcm/clk-bcm2835.c
437fb9
@@ -1651,30 +1651,10 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
437fb9
 		.fixed_divider = 1,
437fb9
 		.flags = CLK_SET_RATE_PARENT),
437fb9
 
437fb9
-	/* PLLB is used for the ARM's clock. */
437fb9
-	[BCM2835_PLLB]		= REGISTER_PLL(
437fb9
-		.name = "pllb",
437fb9
-		.cm_ctrl_reg = CM_PLLB,
437fb9
-		.a2w_ctrl_reg = A2W_PLLB_CTRL,
437fb9
-		.frac_reg = A2W_PLLB_FRAC,
437fb9
-		.ana_reg_base = A2W_PLLB_ANA0,
437fb9
-		.reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE,
437fb9
-		.lock_mask = CM_LOCK_FLOCKB,
437fb9
-
437fb9
-		.ana = &bcm2835_ana_default,
437fb9
-
437fb9
-		.min_rate = 600000000u,
437fb9
-		.max_rate = 3000000000u,
437fb9
-		.max_fb_rate = BCM2835_MAX_FB_RATE),
437fb9
-	[BCM2835_PLLB_ARM]	= REGISTER_PLL_DIV(
437fb9
-		.name = "pllb_arm",
437fb9
-		.source_pll = "pllb",
437fb9
-		.cm_reg = CM_PLLB,
437fb9
-		.a2w_reg = A2W_PLLB_ARM,
437fb9
-		.load_mask = CM_PLLB_LOADARM,
437fb9
-		.hold_mask = CM_PLLB_HOLDARM,
437fb9
-		.fixed_divider = 1,
437fb9
-		.flags = CLK_SET_RATE_PARENT),
437fb9
+	/*
437fb9
+	 * PLLB is used for the ARM's clock. Controlled by firmware, see
437fb9
+	 * clk-raspberrypi.c.
437fb9
+	 */
437fb9
 
437fb9
 	/*
437fb9
 	 * PLLC is the core PLL, used to drive the core VPU clock.
437fb9
-- 
437fb9
2.21.0
437fb9
437fb9
From 64482a97a0a2f14ebdbfe80a8eb0e063d293807b Mon Sep 17 00:00:00 2001
437fb9
From: Peter Robinson <pbrobinson@gmail.com>
437fb9
Date: Wed, 12 Jun 2019 17:23:12 +0100
437fb9
Subject: [PATCH 2/5] clk: bcm283x: add driver interfacing with Raspberry Pi's
437fb9
 firmware
437fb9
437fb9
Raspberry Pi's firmware offers an interface though which update it's
437fb9
clock's frequencies. This is specially useful in order to change the CPU
437fb9
clock (pllb_arm) which is 'owned' by the firmware and we're unable to
437fb9
scale using the register interface provided by clk-bcm2835.
437fb9
437fb9
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
Acked-by: Eric Anholt <eric@anholt.net>
437fb9
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
437fb9
---
437fb9
 drivers/clk/bcm/Kconfig           |   7 +
437fb9
 drivers/clk/bcm/Makefile          |   1 +
437fb9
 drivers/clk/bcm/clk-raspberrypi.c | 300 ++++++++++++++++++++++++++++++
437fb9
 3 files changed, 308 insertions(+)
437fb9
 create mode 100644 drivers/clk/bcm/clk-raspberrypi.c
437fb9
437fb9
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
437fb9
index 29ee7b776cd4..a4a2775d65e1 100644
437fb9
--- a/drivers/clk/bcm/Kconfig
437fb9
+++ b/drivers/clk/bcm/Kconfig
437fb9
@@ -64,3 +64,10 @@ config CLK_BCM_SR
437fb9
 	default ARCH_BCM_IPROC
437fb9
 	help
437fb9
 	  Enable common clock framework support for the Broadcom Stingray SoC
437fb9
+
437fb9
+config CLK_RASPBERRYPI
437fb9
+	tristate "Raspberry Pi firmware based clock support"
437fb9
+	depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
437fb9
+	help
437fb9
+	  Enable common clock framework support for Raspberry Pi's firmware
437fb9
+	  dependent clocks
437fb9
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
437fb9
index 002661d39128..eb7159099d82 100644
437fb9
--- a/drivers/clk/bcm/Makefile
437fb9
+++ b/drivers/clk/bcm/Makefile
437fb9
@@ -7,6 +7,7 @@ obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm21664.o
437fb9
 obj-$(CONFIG_COMMON_CLK_IPROC)	+= clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
437fb9
 obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
437fb9
 obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835-aux.o
437fb9
+obj-$(CONFIG_CLK_RASPBERRYPI)	+= clk-raspberrypi.o
437fb9
 obj-$(CONFIG_ARCH_BCM_53573)	+= clk-bcm53573-ilp.o
437fb9
 obj-$(CONFIG_CLK_BCM_CYGNUS)	+= clk-cygnus.o
437fb9
 obj-$(CONFIG_CLK_BCM_HR2)	+= clk-hr2.o
437fb9
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
437fb9
new file mode 100644
437fb9
index 000000000000..467933767106
437fb9
--- /dev/null
437fb9
+++ b/drivers/clk/bcm/clk-raspberrypi.c
437fb9
@@ -0,0 +1,300 @@
437fb9
+// SPDX-License-Identifier: GPL-2.0+
437fb9
+/*
437fb9
+ * Raspberry Pi driver for firmware controlled clocks
437fb9
+ *
437fb9
+ * Even though clk-bcm2835 provides an interface to the hardware registers for
437fb9
+ * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it.
437fb9
+ * We're not allowed to change it directly as we might race with the
437fb9
+ * over-temperature and under-voltage protections provided by the firmware.
437fb9
+ *
437fb9
+ * Copyright (C) 2019 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
+ */
437fb9
+
437fb9
+#include <linux/clkdev.h>
437fb9
+#include <linux/clk-provider.h>
437fb9
+#include <linux/io.h>
437fb9
+#include <linux/module.h>
437fb9
+#include <linux/platform_device.h>
437fb9
+
437fb9
+#include <soc/bcm2835/raspberrypi-firmware.h>
437fb9
+
437fb9
+#define RPI_FIRMWARE_ARM_CLK_ID		0x000000003
437fb9
+
437fb9
+#define RPI_FIRMWARE_STATE_ENABLE_BIT	BIT(0)
437fb9
+#define RPI_FIRMWARE_STATE_WAIT_BIT	BIT(1)
437fb9
+
437fb9
+/*
437fb9
+ * Even though the firmware interface alters 'pllb' the frequencies are
437fb9
+ * provided as per 'pllb_arm'. We need to scale before passing them trough.
437fb9
+ */
437fb9
+#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE	2
437fb9
+
437fb9
+#define A2W_PLL_FRAC_BITS		20
437fb9
+
437fb9
+struct raspberrypi_clk {
437fb9
+	struct device *dev;
437fb9
+	struct rpi_firmware *firmware;
437fb9
+
437fb9
+	unsigned long min_rate;
437fb9
+	unsigned long max_rate;
437fb9
+
437fb9
+	struct clk_hw pllb;
437fb9
+	struct clk_hw *pllb_arm;
437fb9
+	struct clk_lookup *pllb_arm_lookup;
437fb9
+};
437fb9
+
437fb9
+/*
437fb9
+ * Structure of the message passed to Raspberry Pi's firmware in order to
437fb9
+ * change clock rates. The 'disable_turbo' option is only available to the ARM
437fb9
+ * clock (pllb) which we enable by default as turbo mode will alter multiple
437fb9
+ * clocks at once.
437fb9
+ *
437fb9
+ * Even though we're able to access the clock registers directly we're bound to
437fb9
+ * use the firmware interface as the firmware ultimately takes care of
437fb9
+ * mitigating overheating/undervoltage situations and we would be changing
437fb9
+ * frequencies behind his back.
437fb9
+ *
437fb9
+ * For more information on the firmware interface check:
437fb9
+ * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
437fb9
+ */
437fb9
+struct raspberrypi_firmware_prop {
437fb9
+	__le32 id;
437fb9
+	__le32 val;
437fb9
+	__le32 disable_turbo;
437fb9
+} __packed;
437fb9
+
437fb9
+static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag,
437fb9
+				      u32 clk, u32 *val)
437fb9
+{
437fb9
+	struct raspberrypi_firmware_prop msg = {
437fb9
+		.id = clk,
437fb9
+		.val = *val,
437fb9
+		.disable_turbo = 1,
437fb9
+	};
437fb9
+	int ret;
437fb9
+
437fb9
+	ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg));
437fb9
+	if (ret)
437fb9
+		return ret;
437fb9
+
437fb9
+	*val = msg.val;
437fb9
+
437fb9
+	return 0;
437fb9
+}
437fb9
+
437fb9
+static int raspberrypi_fw_pll_is_on(struct clk_hw *hw)
437fb9
+{
437fb9
+	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
437fb9
+						   pllb);
437fb9
+	u32 val = 0;
437fb9
+	int ret;
437fb9
+
437fb9
+	ret = raspberrypi_clock_property(rpi->firmware,
437fb9
+					 RPI_FIRMWARE_GET_CLOCK_STATE,
437fb9
+					 RPI_FIRMWARE_ARM_CLK_ID, &val;;
437fb9
+	if (ret)
437fb9
+		return 0;
437fb9
+
437fb9
+	return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT);
437fb9
+}
437fb9
+
437fb9
+
437fb9
+static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw,
437fb9
+						 unsigned long parent_rate)
437fb9
+{
437fb9
+	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
437fb9
+						   pllb);
437fb9
+	u32 val = 0;
437fb9
+	int ret;
437fb9
+
437fb9
+	ret = raspberrypi_clock_property(rpi->firmware,
437fb9
+					 RPI_FIRMWARE_GET_CLOCK_RATE,
437fb9
+					 RPI_FIRMWARE_ARM_CLK_ID,
437fb9
+					 &val;;
437fb9
+	if (ret)
437fb9
+		return ret;
437fb9
+
437fb9
+	return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
437fb9
+}
437fb9
+
437fb9
+static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate,
437fb9
+				       unsigned long parent_rate)
437fb9
+{
437fb9
+	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
437fb9
+						   pllb);
437fb9
+	u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
437fb9
+	int ret;
437fb9
+
437fb9
+	ret = raspberrypi_clock_property(rpi->firmware,
437fb9
+					 RPI_FIRMWARE_SET_CLOCK_RATE,
437fb9
+					 RPI_FIRMWARE_ARM_CLK_ID,
437fb9
+					 &new_rate);
437fb9
+	if (ret)
437fb9
+		dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d",
437fb9
+				    clk_hw_get_name(hw), ret);
437fb9
+
437fb9
+	return ret;
437fb9
+}
437fb9
+
437fb9
+/*
437fb9
+ * Sadly there is no firmware rate rounding interface. We borrowed it from
437fb9
+ * clk-bcm2835.
437fb9
+ */
437fb9
+static int raspberrypi_pll_determine_rate(struct clk_hw *hw,
437fb9
+					  struct clk_rate_request *req)
437fb9
+{
437fb9
+	struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk,
437fb9
+						   pllb);
437fb9
+	u64 div, final_rate;
437fb9
+	u32 ndiv, fdiv;
437fb9
+
437fb9
+	/* We can't use req->rate directly as it would overflow */
437fb9
+	final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate);
437fb9
+
437fb9
+	div = (u64)final_rate << A2W_PLL_FRAC_BITS;
437fb9
+	do_div(div, req->best_parent_rate);
437fb9
+
437fb9
+	ndiv = div >> A2W_PLL_FRAC_BITS;
437fb9
+	fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1);
437fb9
+
437fb9
+	final_rate = ((u64)req->best_parent_rate *
437fb9
+					((ndiv << A2W_PLL_FRAC_BITS) + fdiv));
437fb9
+
437fb9
+	req->rate = final_rate >> A2W_PLL_FRAC_BITS;
437fb9
+
437fb9
+	return 0;
437fb9
+}
437fb9
+
437fb9
+static const struct clk_ops raspberrypi_firmware_pll_clk_ops = {
437fb9
+	.is_prepared = raspberrypi_fw_pll_is_on,
437fb9
+	.recalc_rate = raspberrypi_fw_pll_get_rate,
437fb9
+	.set_rate = raspberrypi_fw_pll_set_rate,
437fb9
+	.determine_rate = raspberrypi_pll_determine_rate,
437fb9
+};
437fb9
+
437fb9
+static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi)
437fb9
+{
437fb9
+	u32 min_rate = 0, max_rate = 0;
437fb9
+	struct clk_init_data init;
437fb9
+	int ret;
437fb9
+
437fb9
+	memset(&init, 0, sizeof(init));
437fb9
+
437fb9
+	/* All of the PLLs derive from the external oscillator. */
437fb9
+	init.parent_names = (const char *[]){ "osc" };
437fb9
+	init.num_parents = 1;
437fb9
+	init.name = "pllb";
437fb9
+	init.ops = &raspberrypi_firmware_pll_clk_ops;
437fb9
+	init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
437fb9
+
437fb9
+	/* Get min & max rates set by the firmware */
437fb9
+	ret = raspberrypi_clock_property(rpi->firmware,
437fb9
+					 RPI_FIRMWARE_GET_MIN_CLOCK_RATE,
437fb9
+					 RPI_FIRMWARE_ARM_CLK_ID,
437fb9
+					 &min_rate);
437fb9
+	if (ret) {
437fb9
+		dev_err(rpi->dev, "Failed to get %s min freq: %d\n",
437fb9
+			init.name, ret);
437fb9
+		return ret;
437fb9
+	}
437fb9
+
437fb9
+	ret = raspberrypi_clock_property(rpi->firmware,
437fb9
+					 RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
437fb9
+					 RPI_FIRMWARE_ARM_CLK_ID,
437fb9
+					 &max_rate);
437fb9
+	if (ret) {
437fb9
+		dev_err(rpi->dev, "Failed to get %s max freq: %d\n",
437fb9
+			init.name, ret);
437fb9
+		return ret;
437fb9
+	}
437fb9
+
437fb9
+	if (!min_rate || !max_rate) {
437fb9
+		dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n",
437fb9
+			min_rate, max_rate);
437fb9
+		return -EINVAL;
437fb9
+	}
437fb9
+
437fb9
+	dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n",
437fb9
+		 min_rate, max_rate);
437fb9
+
437fb9
+	rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
437fb9
+	rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE;
437fb9
+
437fb9
+	rpi->pllb.init = &ini;;
437fb9
+
437fb9
+	return devm_clk_hw_register(rpi->dev, &rpi->pllb);
437fb9
+}
437fb9
+
437fb9
+static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi)
437fb9
+{
437fb9
+	rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev,
437fb9
+				"pllb_arm", "pllb",
437fb9
+				CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
437fb9
+				1, 2);
437fb9
+	if (IS_ERR(rpi->pllb_arm)) {
437fb9
+		dev_err(rpi->dev, "Failed to initialize pllb_arm\n");
437fb9
+		return PTR_ERR(rpi->pllb_arm);
437fb9
+	}
437fb9
+
437fb9
+	rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0");
437fb9
+	if (!rpi->pllb_arm_lookup) {
437fb9
+		dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n");
437fb9
+		clk_hw_unregister_fixed_factor(rpi->pllb_arm);
437fb9
+		return -ENOMEM;
437fb9
+	}
437fb9
+
437fb9
+	return 0;
437fb9
+}
437fb9
+
437fb9
+static int raspberrypi_clk_probe(struct platform_device *pdev)
437fb9
+{
437fb9
+	struct device_node *firmware_node;
437fb9
+	struct device *dev = &pdev->dev;
437fb9
+	struct rpi_firmware *firmware;
437fb9
+	struct raspberrypi_clk *rpi;
437fb9
+	int ret;
437fb9
+
437fb9
+	firmware_node = of_find_compatible_node(NULL, NULL,
437fb9
+					"raspberrypi,bcm2835-firmware");
437fb9
+	if (!firmware_node) {
437fb9
+		dev_err(dev, "Missing firmware node\n");
437fb9
+		return -ENOENT;
437fb9
+	}
437fb9
+
437fb9
+	firmware = rpi_firmware_get(firmware_node);
437fb9
+	of_node_put(firmware_node);
437fb9
+	if (!firmware)
437fb9
+		return -EPROBE_DEFER;
437fb9
+
437fb9
+	rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL);
437fb9
+	if (!rpi)
437fb9
+		return -ENOMEM;
437fb9
+
437fb9
+	rpi->dev = dev;
437fb9
+	rpi->firmware = firmware;
437fb9
+
437fb9
+	ret = raspberrypi_register_pllb(rpi);
437fb9
+	if (ret) {
437fb9
+		dev_err(dev, "Failed to initialize pllb, %d\n", ret);
437fb9
+		return ret;
437fb9
+	}
437fb9
+
437fb9
+	ret = raspberrypi_register_pllb_arm(rpi);
437fb9
+	if (ret)
437fb9
+		return ret;
437fb9
+
437fb9
+	return 0;
437fb9
+}
437fb9
+
437fb9
+static struct platform_driver raspberrypi_clk_driver = {
437fb9
+	.driver = {
437fb9
+		.name = "raspberrypi-clk",
437fb9
+	},
437fb9
+	.probe          = raspberrypi_clk_probe,
437fb9
+};
437fb9
+module_platform_driver(raspberrypi_clk_driver);
437fb9
+
437fb9
+MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
437fb9
+MODULE_DESCRIPTION("Raspberry Pi firmware clock driver");
437fb9
+MODULE_LICENSE("GPL");
437fb9
+MODULE_ALIAS("platform:raspberrypi-clk");
437fb9
-- 
437fb9
2.21.0
437fb9
437fb9
From e750e62addb9ee00f47ab4a73c0645d44172ab12 Mon Sep 17 00:00:00 2001
437fb9
From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
Date: Tue, 11 Jun 2019 19:58:38 +0200
437fb9
Subject: [PATCH 3/5] firmware: raspberrypi: register clk device
437fb9
437fb9
Since clk-raspberrypi is tied to the VC4 firmware instead of particular
437fb9
hardware it's registration should be performed by the firmware driver.
437fb9
437fb9
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
Acked-by: Eric Anholt <eric@anholt.net>
437fb9
---
437fb9
 drivers/firmware/raspberrypi.c | 10 ++++++++++
437fb9
 1 file changed, 10 insertions(+)
437fb9
437fb9
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
437fb9
index 61be15d9df7d..da26a584dca0 100644
437fb9
--- a/drivers/firmware/raspberrypi.c
437fb9
+++ b/drivers/firmware/raspberrypi.c
437fb9
@@ -20,6 +20,7 @@
437fb9
 #define MBOX_CHAN_PROPERTY		8
437fb9
 
437fb9
 static struct platform_device *rpi_hwmon;
437fb9
+static struct platform_device *rpi_clk;
437fb9
 
437fb9
 struct rpi_firmware {
437fb9
 	struct mbox_client cl;
437fb9
@@ -207,6 +208,12 @@ rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw)
437fb9
 						  -1, NULL, 0);
437fb9
 }
437fb9
 
437fb9
+static void rpi_register_clk_driver(struct device *dev)
437fb9
+{
437fb9
+	rpi_clk = platform_device_register_data(dev, "raspberrypi-clk",
437fb9
+						-1, NULL, 0);
437fb9
+}
437fb9
+
437fb9
 static int rpi_firmware_probe(struct platform_device *pdev)
437fb9
 {
437fb9
 	struct device *dev = &pdev->dev;
437fb9
@@ -234,6 +241,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
437fb9
 
437fb9
 	rpi_firmware_print_firmware_revision(fw);
437fb9
 	rpi_register_hwmon_driver(dev, fw);
437fb9
+	rpi_register_clk_driver(dev);
437fb9
 
437fb9
 	return 0;
437fb9
 }
437fb9
@@ -254,6 +262,8 @@ static int rpi_firmware_remove(struct platform_device *pdev)
437fb9
 
437fb9
 	platform_device_unregister(rpi_hwmon);
437fb9
 	rpi_hwmon = NULL;
437fb9
+	platform_device_unregister(rpi_clk);
437fb9
+	rpi_clk = NULL;
437fb9
 	mbox_free_channel(fw->chan);
437fb9
 
437fb9
 	return 0;
437fb9
-- 
437fb9
2.21.0
437fb9
437fb9
From af32d83d10976ff357c56adba79fa3cb06e1c32d Mon Sep 17 00:00:00 2001
437fb9
From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
Date: Tue, 11 Jun 2019 19:58:42 +0200
437fb9
Subject: [PATCH 5/5] clk: raspberrypi: register platform device for
437fb9
 raspberrypi-cpufreq
437fb9
437fb9
As 'clk-raspberrypi' depends on RPi's firmware interface, which might be
437fb9
configured as a module, the cpu clock might not be available for the
437fb9
cpufreq driver during it's init process. So we register the
437fb9
'raspberrypi-cpufreq' platform device after the probe sequence succeeds.
437fb9
437fb9
Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
437fb9
Acked-by: Eric Anholt <eric@anholt.net>
437fb9
---
437fb9
 drivers/clk/bcm/clk-raspberrypi.c | 15 +++++++++++++++
437fb9
 1 file changed, 15 insertions(+)
437fb9
437fb9
diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c
437fb9
index 467933767106..7f9b001f8d70 100644
437fb9
--- a/drivers/clk/bcm/clk-raspberrypi.c
437fb9
+++ b/drivers/clk/bcm/clk-raspberrypi.c
437fb9
@@ -34,6 +34,7 @@
437fb9
 struct raspberrypi_clk {
437fb9
 	struct device *dev;
437fb9
 	struct rpi_firmware *firmware;
437fb9
+	struct platform_device *cpufreq;
437fb9
 
437fb9
 	unsigned long min_rate;
437fb9
 	unsigned long max_rate;
437fb9
@@ -272,6 +273,7 @@ static int raspberrypi_clk_probe(struct platform_device *pdev)
437fb9
 
437fb9
 	rpi->dev = dev;
437fb9
 	rpi->firmware = firmware;
437fb9
+	platform_set_drvdata(pdev, rpi);
437fb9
 
437fb9
 	ret = raspberrypi_register_pllb(rpi);
437fb9
 	if (ret) {
437fb9
@@ -283,6 +285,18 @@ static int raspberrypi_clk_probe(struct platform_device *pdev)
437fb9
 	if (ret)
437fb9
 		return ret;
437fb9
 
437fb9
+	rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq",
437fb9
+						     -1, NULL, 0);
437fb9
+
437fb9
+	return 0;
437fb9
+}
437fb9
+
437fb9
+static int raspberrypi_clk_remove(struct platform_device *pdev)
437fb9
+{
437fb9
+	struct raspberrypi_clk *rpi = platform_get_drvdata(pdev);
437fb9
+
437fb9
+	platform_device_unregister(rpi->cpufreq);
437fb9
+
437fb9
 	return 0;
437fb9
 }
437fb9
 
437fb9
@@ -291,6 +305,7 @@ static struct platform_driver raspberrypi_clk_driver = {
437fb9
 		.name = "raspberrypi-clk",
437fb9
 	},
437fb9
 	.probe          = raspberrypi_clk_probe,
437fb9
+	.remove		= raspberrypi_clk_remove,
437fb9
 };
437fb9
 module_platform_driver(raspberrypi_clk_driver);
437fb9
 
437fb9
-- 
437fb9
2.21.0
437fb9