[U-Boot] [PATCH 18/21] clock: implement a driver for the Tegra CAR

Stephen Warren swarren at wwwdotorg.org
Tue Sep 13 18:45:59 CEST 2016


From: Stephen Warren <swarren at nvidia.com>

Implement a clock uclass driver for the Tegra CAR. This allows clients to
use standard clock APIs on Tegra. This device is intended to be
instantiated by the core Tegra CAR driver, rather than being instantiated
directly from DT. The implementation uses the existing custom Tegra-
specific clock APIs to avoid coupling the series with significant
refactoring of the existing Tegra clock/clock code. The driver currently
only supports peripheral clocks, and avoids support for other clocks such
as PLLs and external clocks. This should be sufficient to convert over all
Tegra peripheral drivers, and avoids a complex implementation which calls
different Tegra-specific clock APIs based on the type of clock being
manipulated.

Signed-off-by: Stephen Warren <swarren at nvidia.com>
---
 drivers/clk/tegra/Kconfig         |   7 +++
 drivers/clk/tegra/Makefile        |   1 +
 drivers/clk/tegra/tegra-car-clk.c | 103 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+)
 create mode 100644 drivers/clk/tegra/tegra-car-clk.c

diff --git a/drivers/clk/tegra/Kconfig b/drivers/clk/tegra/Kconfig
index 659fe022c2af..ce80b1ff3ea4 100644
--- a/drivers/clk/tegra/Kconfig
+++ b/drivers/clk/tegra/Kconfig
@@ -1,3 +1,10 @@
+config TEGRA_CAR_CLOCK
+	bool "Enable Tegra CAR-based clock driver"
+	depends on TEGRA_CAR
+	help
+	  Enable support for manipulating Tegra's on-SoC clocks via direct
+	  register access to the Tegra CAR (Clock And Reset controller).
+
 config TEGRA186_CLOCK
 	bool "Enable Tegra186 BPMP-based clock driver"
 	depends on TEGRA186_BPMP
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index f32998ccc27d..0fcc5205a70b 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -2,4 +2,5 @@
 #
 # SPDX-License-Identifier: GPL-2.0
 
+obj-$(CONFIG_TEGRA_CAR_CLOCK) += tegra-car-clk.o
 obj-$(CONFIG_TEGRA186_CLOCK) += tegra186-clk.o
diff --git a/drivers/clk/tegra/tegra-car-clk.c b/drivers/clk/tegra/tegra-car-clk.c
new file mode 100644
index 000000000000..b8a2c82a25c0
--- /dev/null
+++ b/drivers/clk/tegra/tegra-car-clk.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/clk_rst.h>
+
+static int tegra_car_clk_request(struct clk *clk)
+{
+	debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+	      clk->id);
+
+	/*
+	 * Note that the first PERIPH_ID_COUNT clock IDs (where the value
+	 * varies per SoC) are the peripheral clocks, which use a numbering
+	 * scheme that matches HW registers 1:1. There are other clock IDs
+	 * beyond this that are assigned arbitrarily by the Tegra CAR DT
+	 * binding. Due to the implementation of this driver, it currently
+	 * only supports the peripheral IDs.
+	 */
+	if (clk->id >= PERIPH_ID_COUNT)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int tegra_car_clk_free(struct clk *clk)
+{
+	debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+	      clk->id);
+
+	return 0;
+}
+
+static ulong tegra_car_clk_get_rate(struct clk *clk)
+{
+	enum clock_id parent;
+
+	debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+	      clk->id);
+
+	parent = clock_get_periph_parent(clk->id);
+	return clock_get_periph_rate(clk->id, parent);
+}
+
+static ulong tegra_car_clk_set_rate(struct clk *clk, ulong rate)
+{
+	enum clock_id parent;
+
+	debug("%s(clk=%p, rate=%lu) (dev=%p, id=%lu)\n", __func__, clk, rate,
+	      clk->dev, clk->id);
+
+	parent = clock_get_periph_parent(clk->id);
+	return clock_adjust_periph_pll_div(clk->id, parent, rate, NULL);
+}
+
+static int tegra_car_clk_enable(struct clk *clk)
+{
+	debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+	      clk->id);
+
+	clock_enable(clk->id);
+
+	return 0;
+}
+
+static int tegra_car_clk_disable(struct clk *clk)
+{
+	debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
+	      clk->id);
+
+	clock_disable(clk->id);
+
+	return 0;
+}
+
+static struct clk_ops tegra_car_clk_ops = {
+	.request = tegra_car_clk_request,
+	.free = tegra_car_clk_free,
+	.get_rate = tegra_car_clk_get_rate,
+	.set_rate = tegra_car_clk_set_rate,
+	.enable = tegra_car_clk_enable,
+	.disable = tegra_car_clk_disable,
+};
+
+static int tegra_car_clk_probe(struct udevice *dev)
+{
+	debug("%s(dev=%p)\n", __func__, dev);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(tegra_car_clk) = {
+	.name = "tegra_car_clk",
+	.id = UCLASS_CLK,
+	.probe = tegra_car_clk_probe,
+	.ops = &tegra_car_clk_ops,
+};
-- 
2.9.3



More information about the U-Boot mailing list