@@ -1,3 +1,3 @@
# Makefile for device boot constraints
-obj-y := core.o supply.o
+obj-y := clk.o core.o supply.o
new file mode 100644
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#define pr_fmt(fmt) "Clock Boot Constraints: " fmt
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "core.h"
+
+struct constraint_clk {
+ struct dev_boot_constraint_clk_info clk_info;
+ struct clk *clk;
+};
+
+int constraint_clk_add(struct constraint *constraint, void *data)
+{
+ struct dev_boot_constraint_clk_info *clk_info = data;
+ struct constraint_clk *cclk;
+ struct device *dev = constraint->cdev->dev;
+ int ret;
+
+ cclk = kzalloc(sizeof(*cclk), GFP_KERNEL);
+ if (!cclk)
+ return -ENOMEM;
+
+ cclk->clk = clk_get(dev, clk_info->name);
+ if (IS_ERR(cclk->clk)) {
+ ret = PTR_ERR(cclk->clk);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(dev, "clk_get() failed for %s (%d)\n",
+ clk_info->name, ret);
+ }
+ goto free;
+ }
+
+ ret = clk_prepare_enable(cclk->clk);
+ if (ret) {
+ dev_err(dev, "clk_prepare_enable() %s failed (%d)\n",
+ clk_info->name, ret);
+ goto put_clk;
+ }
+
+ cclk->clk_info.name = kstrdup_const(clk_info->name, GFP_KERNEL);
+ constraint->private = cclk;
+
+ return 0;
+
+put_clk:
+ clk_put(cclk->clk);
+free:
+ kfree(cclk);
+
+ return ret;
+}
+
+void constraint_clk_remove(struct constraint *constraint)
+{
+ struct constraint_clk *cclk = constraint->private;
+
+ kfree_const(cclk->clk_info.name);
+ clk_disable_unprepare(cclk->clk);
+ clk_put(cclk->clk);
+ kfree(cclk);
+}
@@ -105,6 +105,10 @@ static struct constraint *constraint_allocate(struct constraint_dev *cdev,
void (*remove)(struct constraint *constraint);
switch (type) {
+ case DEV_BOOT_CONSTRAINT_CLK:
+ add = constraint_clk_add;
+ remove = constraint_clk_remove;
+ break;
case DEV_BOOT_CONSTRAINT_SUPPLY:
add = constraint_supply_add;
remove = constraint_supply_remove;
@@ -30,6 +30,9 @@ struct constraint {
};
/* Forward declarations of constraint specific callbacks */
+int constraint_clk_add(struct constraint *constraint, void *data);
+void constraint_clk_remove(struct constraint *constraint);
+
int constraint_supply_add(struct constraint *constraint, void *data);
void constraint_supply_remove(struct constraint *constraint);
@@ -15,9 +15,14 @@
struct device;
enum dev_boot_constraint_type {
+ DEV_BOOT_CONSTRAINT_CLK,
DEV_BOOT_CONSTRAINT_SUPPLY,
};
+struct dev_boot_constraint_clk_info {
+ const char *name;
+};
+
struct dev_boot_constraint_supply_info {
const char *name;
unsigned int u_volt_min;