summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-06-23 15:39:15 -0600
committerSimon Glass <sjg@chromium.org>2015-07-21 17:39:29 -0600
commitf26c8a8e77629cf9de36a697ea5513f9184a2319 (patch)
treea6466bcd31947349287b062fb92d30683b8b4f5a /drivers
parent30db918768396caaae43f644f7ca9e41f461ab75 (diff)
downloadblackbird-obmc-uboot-f26c8a8e77629cf9de36a697ea5513f9184a2319.tar.gz
blackbird-obmc-uboot-f26c8a8e77629cf9de36a697ea5513f9184a2319.zip
dm: Add a clock uclass
Clocks are an important feature of platforms and have become increasing complex with time. Most modern SoCs have multiple PLLs and dozens of clock dividers which distribute clocks to on-chip peripherals. Some SoC implementations have a clock API which is private to that SoC family, e.g. Tegra and Exynos. This is useful but it would be better to have a common API that can be understood and used throughout U-Boot. Add a simple clock API as a starting point. It supports querying and setting the rate of a clock. Each clock is a device. To reduce memory and processing overhead the concept of peripheral clocks is provided. These do not need to be explicit devices - it is possible to write a driver that can adjust the I2C clock (for example) without an explicit I2C clock device. This can dramatically reduce the number of devices (and associated overhead) in a complex SoC. Clocks are referenced by a number, and it is expected that SoCs will define that numbering themselves via an enum. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/clk/Kconfig19
-rw-r--r--drivers/clk/Makefile8
-rw-r--r--drivers/clk/clk-uclass.c58
5 files changed, 88 insertions, 0 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 64c27931aa..092bc02b30 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,7 @@
menu "Device Drivers"
+source "drivers/clk/Kconfig"
+
source "drivers/core/Kconfig"
source "drivers/cpu/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 4f859dc306..5a35148ead 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_CLK) += clk/
obj-$(CONFIG_DM) += core/
obj-$(CONFIG_DM_DEMO) += demo/
obj-$(CONFIG_BIOSEMU) += bios_emulator/
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
new file mode 100644
index 0000000000..07eb54c597
--- /dev/null
+++ b/drivers/clk/Kconfig
@@ -0,0 +1,19 @@
+config CLK
+ bool "Enable clock driver support"
+ depends on DM
+ help
+ This allows drivers to be provided for clock generators, including
+ oscillators and PLLs. Devices can use a common clock API to request
+ a particular clock rate and check on available clocks. Clocks can
+ feed into other clocks in a tree structure, with multiplexers to
+ choose the source for each clock.
+
+config SPL_CLK_SUPPORT
+ bool "Enable clock support in SPL"
+ depends on CLK
+ help
+ The clock subsystem adds a small amount of overhead to the image.
+ If this is acceptable and you have a need to use clock drivers in
+ SPL, enable this option. It might provide a cleaner interface to
+ setting up clocks within SPL, and allows the same drivers to be
+ used as U-Boot proper.
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
new file mode 100644
index 0000000000..b51cf23850
--- /dev/null
+++ b/drivers/clk/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_CLK) += clk-uclass.o
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
new file mode 100644
index 0000000000..73dfd7d016
--- /dev/null
+++ b/drivers/clk/clk-uclass.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+ulong clk_get_rate(struct udevice *dev)
+{
+ struct clk_ops *ops = clk_get_ops(dev);
+
+ if (!ops->get_rate)
+ return -ENOSYS;
+
+ return ops->get_rate(dev);
+}
+
+ulong clk_set_rate(struct udevice *dev, ulong rate)
+{
+ struct clk_ops *ops = clk_get_ops(dev);
+
+ if (!ops->set_rate)
+ return -ENOSYS;
+
+ return ops->set_rate(dev, rate);
+}
+
+ulong clk_get_periph_rate(struct udevice *dev, int periph)
+{
+ struct clk_ops *ops = clk_get_ops(dev);
+
+ if (!ops->get_periph_rate)
+ return -ENOSYS;
+
+ return ops->get_periph_rate(dev, periph);
+}
+
+ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+ struct clk_ops *ops = clk_get_ops(dev);
+
+ if (!ops->set_periph_rate)
+ return -ENOSYS;
+
+ return ops->set_periph_rate(dev, periph, rate);
+}
+
+UCLASS_DRIVER(clk) = {
+ .id = UCLASS_CLK,
+ .name = "clk",
+};
OpenPOWER on IntegriCloud