mirror of https://github.com/OpenIPC/firmware.git
193 lines
4.5 KiB
Diff
193 lines
4.5 KiB
Diff
--- linux-4.9.37/drivers/clk/goke/clk.c 1970-01-01 03:00:00.000000000 +0300
|
|
+++ linux-4.9.y/drivers/clk/goke/clk.c 2021-06-07 13:01:33.000000000 +0300
|
|
@@ -0,0 +1,188 @@
|
|
+/*
|
|
+ * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/clkdev.h>
|
|
+#include <linux/clk-provider.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+#include "clk.h"
|
|
+
|
|
+static DEFINE_SPINLOCK(gk_clk_lock);
|
|
+
|
|
+struct gk_clock_data *gk_clk_init(struct device_node *np,
|
|
+ int nr_clks)
|
|
+{
|
|
+ struct gk_clock_data *clk_data;
|
|
+ struct clk **clk_table;
|
|
+ void __iomem *base;
|
|
+
|
|
+ base = of_iomap(np, 0);
|
|
+ if (!base) {
|
|
+ pr_err("%s: failed to map clock registers\n", __func__);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
|
|
+ if (!clk_data) {
|
|
+ pr_err("%s: could not allocate clock data\n", __func__);
|
|
+ goto err;
|
|
+ }
|
|
+ clk_data->base = base;
|
|
+
|
|
+ clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
|
|
+ if (!clk_table) {
|
|
+ pr_err("%s: could not allocate clock lookup table\n", __func__);
|
|
+ goto err_data;
|
|
+ }
|
|
+ clk_data->clk_data.clks = clk_table;
|
|
+ clk_data->clk_data.clk_num = nr_clks;
|
|
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
|
|
+ return clk_data;
|
|
+err_data:
|
|
+ kfree(clk_data);
|
|
+err:
|
|
+ return NULL;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(gk_clk_init);
|
|
+
|
|
+int gk_clk_register_fixed_rate(const struct gk_fixed_rate_clock *clks,
|
|
+ int nums, struct gk_clock_data *data)
|
|
+{
|
|
+ struct clk *clk;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < nums; i++) {
|
|
+ clk = clk_register_fixed_rate(NULL, clks[i].name,
|
|
+ clks[i].parent_name,
|
|
+ clks[i].flags,
|
|
+ clks[i].fixed_rate);
|
|
+ if (IS_ERR(clk)) {
|
|
+ pr_err("%s: failed to register clock %s\n",
|
|
+ __func__, clks[i].name);
|
|
+ goto err;
|
|
+ }
|
|
+ data->clk_data.clks[clks[i].id] = clk;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ while (i--)
|
|
+ clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
|
|
+
|
|
+ return PTR_ERR(clk);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(gk_clk_register_fixed_rate);
|
|
+
|
|
+int gk_clk_register_fixed_factor(const struct gk_fixed_factor_clock *clks,
|
|
+ int nums,
|
|
+ struct gk_clock_data *data)
|
|
+{
|
|
+ struct clk *clk;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < nums; i++) {
|
|
+ clk = clk_register_fixed_factor(NULL, clks[i].name,
|
|
+ clks[i].parent_name,
|
|
+ clks[i].flags, clks[i].mult,
|
|
+ clks[i].div);
|
|
+ if (IS_ERR(clk)) {
|
|
+ pr_err("%s: failed to register clock %s\n",
|
|
+ __func__, clks[i].name);
|
|
+ goto err;
|
|
+ }
|
|
+ data->clk_data.clks[clks[i].id] = clk;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ while (i--)
|
|
+ clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
|
|
+
|
|
+ return PTR_ERR(clk);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(gk_clk_register_fixed_factor);
|
|
+
|
|
+int gk_clk_register_mux(const struct gk_mux_clock *clks,
|
|
+ int nums, struct gk_clock_data *data)
|
|
+{
|
|
+ struct clk *clk;
|
|
+ void __iomem *base = data->base;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < nums; i++) {
|
|
+ u32 mask = BIT(clks[i].width) - 1;
|
|
+
|
|
+ clk = clk_register_mux_table(NULL, clks[i].name,
|
|
+ clks[i].parent_names,
|
|
+ clks[i].num_parents, clks[i].flags,
|
|
+ base + clks[i].offset, clks[i].shift,
|
|
+ mask, clks[i].mux_flags,
|
|
+ clks[i].table, &gk_clk_lock);
|
|
+ if (IS_ERR(clk)) {
|
|
+ pr_err("%s: failed to register clock %s\n",
|
|
+ __func__, clks[i].name);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ if (clks[i].alias)
|
|
+ clk_register_clkdev(clk, clks[i].alias, NULL);
|
|
+
|
|
+ data->clk_data.clks[clks[i].id] = clk;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ while (i--)
|
|
+ clk_unregister_mux(data->clk_data.clks[clks[i].id]);
|
|
+
|
|
+ return PTR_ERR(clk);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(gk_clk_register_mux);
|
|
+
|
|
+
|
|
+int gk_clk_register_gate(const struct gk_gate_clock *clks,
|
|
+ int nums, struct gk_clock_data *data)
|
|
+{
|
|
+ struct clk *clk;
|
|
+ void __iomem *base = data->base;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < nums; i++) {
|
|
+ clk = clk_register_gate(NULL, clks[i].name,
|
|
+ clks[i].parent_name,
|
|
+ clks[i].flags,
|
|
+ base + clks[i].offset,
|
|
+ clks[i].bit_idx,
|
|
+ clks[i].gate_flags,
|
|
+ &gk_clk_lock);
|
|
+ if (IS_ERR(clk)) {
|
|
+ pr_err("%s: failed to register clock %s\n",
|
|
+ __func__, clks[i].name);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ if (clks[i].alias)
|
|
+ clk_register_clkdev(clk, clks[i].alias, NULL);
|
|
+
|
|
+ data->clk_data.clks[clks[i].id] = clk;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ while (i--)
|
|
+ clk_unregister_gate(data->clk_data.clks[clks[i].id]);
|
|
+
|
|
+ return PTR_ERR(clk);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(gk_clk_register_gate);
|
|
\ No newline at end of file
|