aboutsummaryrefslogtreecommitdiff
path: root/drivers/clk/clk-uclass.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2016-06-17 09:44:00 -0600
committerSimon Glass <sjg@chromium.org>2016-06-19 17:05:55 -0600
commit135aa95002646c46e89de93fa36adad1b010548f (patch)
treeb601e08f7d91c7e2cda127d59f8f81128d0cb1ac /drivers/clk/clk-uclass.c
parent4581b717b1bf0fb04e7d9fcaf3d4c23d357154ac (diff)
downloadu-boot-135aa95002646c46e89de93fa36adad1b010548f.zip
u-boot-135aa95002646c46e89de93fa36adad1b010548f.tar.gz
u-boot-135aa95002646c46e89de93fa36adad1b010548f.tar.bz2
clk: convert API to match reset/mailbox style
The following changes are made to the clock API: * The concept of "clocks" and "peripheral clocks" are unified; each clock provider now implements a single set of clocks. This provides a simpler conceptual interface to clients, and better aligns with device tree clock bindings. * Clocks are now identified with a single "struct clk", rather than requiring clients to store the clock provider device and clock identity values separately. For simple clock consumers, this isolates clients from internal details of the clock API. * clk.h is split so it only contains the client/consumer API, whereas clk-uclass.h contains the provider API. This aligns with the recently added reset and mailbox APIs. * clk_ops .of_xlate(), .request(), and .free() are added so providers can customize these operations if needed. This also aligns with the recently added reset and mailbox APIs. * clk_disable() is added. * All users of the current clock APIs are updated. * Sandbox clock tests are updated to exercise clock lookup via DT, and clock enable/disable. * rkclk_get_clk() is removed and replaced with standard APIs. Buildman shows no clock-related errors for any board for which buildman can download a toolchain. test/py passes for sandbox (which invokes the dm clk test amongst others). Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/clk/clk-uclass.c')
-rw-r--r--drivers/clk/clk-uclass.c202
1 files changed, 145 insertions, 57 deletions
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index b483c1e..6e4d672 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -1,91 +1,78 @@
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
+ * Copyright (c) 2016, NVIDIA CORPORATION.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <clk.h>
+#include <clk-uclass.h>
#include <dm.h>
#include <errno.h>
-#include <dm/lists.h>
-#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
-ulong clk_get_rate(struct udevice *dev)
+static inline struct clk_ops *clk_dev_ops(struct udevice *dev)
{
- struct clk_ops *ops = clk_get_ops(dev);
-
- if (!ops->get_rate)
- return -ENOSYS;
-
- return ops->get_rate(dev);
+ return (struct clk_ops *)dev->driver->ops;
}
-ulong clk_set_rate(struct udevice *dev, ulong rate)
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+#ifdef CONFIG_SPL_BUILD
+int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
{
- struct clk_ops *ops = clk_get_ops(dev);
+ int ret;
+ u32 cell[2];
- if (!ops->set_rate)
+ if (index != 0)
return -ENOSYS;
-
- return ops->set_rate(dev, rate);
+ assert(clk);
+ ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
+ if (ret)
+ return ret;
+ ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks",
+ cell, 2);
+ if (ret)
+ return ret;
+ clk->id = cell[1];
+ return 0;
}
-int clk_enable(struct udevice *dev, int periph)
+int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
{
- struct clk_ops *ops = clk_get_ops(dev);
-
- if (!ops->enable)
- return -ENOSYS;
-
- return ops->enable(dev, periph);
+ return -ENOSYS;
}
-
-ulong clk_get_periph_rate(struct udevice *dev, int periph)
+#else
+static int clk_of_xlate_default(struct clk *clk,
+ struct fdtdec_phandle_args *args)
{
- struct clk_ops *ops = clk_get_ops(dev);
+ debug("%s(clk=%p)\n", __func__, clk);
- 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 (args->args_count > 1) {
+ debug("Invaild args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
- if (!ops->set_periph_rate)
- return -ENOSYS;
+ if (args->args_count)
+ clk->id = args->args[0];
+ else
+ clk->id = 0;
- return ops->set_periph_rate(dev, periph, rate);
+ return 0;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp)
+int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
{
int ret;
-#ifdef CONFIG_SPL_BUILD
- u32 cell[2];
-
- if (index != 0)
- return -ENOSYS;
- assert(*clk_devp);
- ret = uclass_get_device(UCLASS_CLK, 0, clk_devp);
- if (ret)
- return ret;
- ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks",
- cell, 2);
- if (ret)
- return ret;
- return cell[1];
-#else
struct fdtdec_phandle_args args;
+ struct udevice *dev_clk;
+ struct clk_ops *ops;
+
+ debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
- assert(*clk_devp);
+ assert(clk);
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
"clocks", "#clock-cells", 0, index,
&args);
@@ -95,16 +82,117 @@ int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp)
return ret;
}
- ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp);
+ ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev_clk);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
}
- return args.args_count > 0 ? args.args[0] : 0;
-#endif
+ ops = clk_dev_ops(dev_clk);
+
+ if (ops->of_xlate)
+ ret = ops->of_xlate(clk, &args);
+ else
+ ret = clk_of_xlate_default(clk, &args);
+ if (ret) {
+ debug("of_xlate() failed: %d\n", ret);
+ return ret;
+ }
+
+ return clk_request(dev_clk, clk);
+}
+
+int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
+{
+ int index;
+
+ debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk);
+
+ index = fdt_find_string(gd->fdt_blob, dev->of_offset, "clock-names",
+ name);
+ if (index < 0) {
+ debug("fdt_find_string() failed: %d\n", index);
+ return index;
+ }
+
+ return clk_get_by_index(dev, index, clk);
}
#endif
+#endif
+
+int clk_request(struct udevice *dev, struct clk *clk)
+{
+ struct clk_ops *ops = clk_dev_ops(dev);
+
+ debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
+
+ clk->dev = dev;
+
+ if (!ops->request)
+ return 0;
+
+ return ops->request(clk);
+}
+
+int clk_free(struct clk *clk)
+{
+ struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+ debug("%s(clk=%p)\n", __func__, clk);
+
+ if (!ops->free)
+ return 0;
+
+ return ops->free(clk);
+}
+
+ulong clk_get_rate(struct clk *clk)
+{
+ struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+ debug("%s(clk=%p)\n", __func__, clk);
+
+ if (!ops->get_rate)
+ return -ENOSYS;
+
+ return ops->get_rate(clk);
+}
+
+ulong clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+ debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
+
+ if (!ops->set_rate)
+ return -ENOSYS;
+
+ return ops->set_rate(clk, rate);
+}
+
+int clk_enable(struct clk *clk)
+{
+ struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+ debug("%s(clk=%p)\n", __func__, clk);
+
+ if (!ops->enable)
+ return -ENOSYS;
+
+ return ops->enable(clk);
+}
+
+int clk_disable(struct clk *clk)
+{
+ struct clk_ops *ops = clk_dev_ops(clk->dev);
+
+ debug("%s(clk=%p)\n", __func__, clk);
+
+ if (!ops->disable)
+ return -ENOSYS;
+
+ return ops->disable(clk);
+}
UCLASS_DRIVER(clk) = {
.id = UCLASS_CLK,