From a5969cabbb4660eab42b6ef0412cbbd1200cf14d Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 12 Oct 2024 07:10:09 +0000
Subject: [PATCH] 修改led为gpio
---
kernel/drivers/clk/rockchip/clk.c | 359 ++++++++++++++++++++++++++++++++---------------------------
1 files changed, 195 insertions(+), 164 deletions(-)
diff --git a/kernel/drivers/clk/rockchip/clk.c b/kernel/drivers/clk/rockchip/clk.c
index 06769a0..1c91007 100644
--- a/kernel/drivers/clk/rockchip/clk.c
+++ b/kernel/drivers/clk/rockchip/clk.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
@@ -11,26 +12,21 @@
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* Copyright (c) 2013 Linaro Ltd.
* Author: Thomas Abraham <thomas.ab@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/reboot.h>
#include <linux/rational.h>
#include "clk.h"
+
+#ifdef MODULE
+static HLIST_HEAD(clk_ctx_list);
+#endif
/**
* Register a clock branch.
@@ -52,7 +48,7 @@
u8 gate_shift, u8 gate_flags, unsigned long flags,
spinlock_t *lock)
{
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_mux *mux = NULL;
struct clk_gate *gate = NULL;
struct clk_divider *div = NULL;
@@ -110,20 +106,18 @@
: &clk_divider_ops;
}
- clk = clk_register_composite(NULL, name, parent_names, num_parents,
- mux ? &mux->hw : NULL, mux_ops,
- div ? &div->hw : NULL, div_ops,
- gate ? &gate->hw : NULL, gate_ops,
- flags);
-
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- goto err_composite;
+ hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+ mux ? &mux->hw : NULL, mux_ops,
+ div ? &div->hw : NULL, div_ops,
+ gate ? &gate->hw : NULL, gate_ops,
+ flags);
+ if (IS_ERR(hw)) {
+ kfree(div);
+ kfree(gate);
+ return ERR_CAST(hw);
}
- return clk;
-err_composite:
- kfree(div);
+ return hw->clk;
err_div:
kfree(gate);
err_gate:
@@ -194,22 +188,23 @@
unsigned long p_rate, p_parent_rate;
struct clk_hw *p_parent;
unsigned long scale;
- u32 div;
+
+ if (rate == 0) {
+ pr_warn("%s p_rate(%ld), rate(%ld), maybe invalid frequency setting!\n",
+ clk_hw_get_name(hw), *parent_rate, rate);
+ *m = 0;
+ *n = 1;
+ return;
+ }
p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
- if (((rate * 20 > p_rate) && (p_rate % rate != 0)) ||
- (fd->max_prate && fd->max_prate < p_rate)) {
+ if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
if (!p_parent) {
*parent_rate = p_rate;
} else {
p_parent_rate = clk_hw_get_rate(p_parent);
*parent_rate = p_parent_rate;
- if (fd->max_prate && p_parent_rate > fd->max_prate) {
- div = DIV_ROUND_UP(p_parent_rate,
- fd->max_prate);
- *parent_rate = p_parent_rate / div;
- }
}
if (*parent_rate < rate * 20) {
@@ -238,6 +233,13 @@
* for m and n. In the result it will be the nearest rate left shifted
* by (scale - fd->nwidth) bits.
*/
+ if (*parent_rate == 0) {
+ pr_warn("%s p_rate(%ld), rate(%ld), maybe invalid frequency setting!\n",
+ clk_hw_get_name(hw), *parent_rate, rate);
+ *m = 0;
+ *n = 1;
+ return;
+ }
scale = fls_long(*parent_rate / rate - 1);
if (scale > fd->nwidth)
rate <<= scale - fd->nwidth;
@@ -253,10 +255,10 @@
void __iomem *base, int muxdiv_offset, u8 div_flags,
int gate_offset, u8 gate_shift, u8 gate_flags,
unsigned long flags, struct rockchip_clk_branch *child,
- unsigned long max_prate, spinlock_t *lock)
+ spinlock_t *lock)
{
+ struct clk_hw *hw;
struct rockchip_clk_frac *frac;
- struct clk *clk;
struct clk_gate *gate = NULL;
struct clk_fractional_divider *div = NULL;
const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
@@ -294,22 +296,21 @@
div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift;
div->lock = lock;
div->approximation = rockchip_fractional_approximation;
- div->max_prate = max_prate;
div_ops = &clk_fractional_divider_ops;
- clk = clk_register_composite(NULL, name, parent_names, num_parents,
- NULL, NULL,
- &div->hw, div_ops,
- gate ? &gate->hw : NULL, gate_ops,
- flags | CLK_SET_RATE_UNGATE);
- if (IS_ERR(clk)) {
+ hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+ NULL, NULL,
+ &div->hw, div_ops,
+ gate ? &gate->hw : NULL, gate_ops,
+ flags | CLK_SET_RATE_UNGATE);
+ if (IS_ERR(hw)) {
kfree(frac);
- return clk;
+ return ERR_CAST(hw);
}
if (child) {
struct clk_mux *frac_mux = &frac->mux;
- struct clk_init_data init = {};
+ struct clk_init_data init;
struct clk *mux_clk;
int ret;
@@ -336,7 +337,7 @@
mux_clk = clk_register(NULL, &frac_mux->hw);
if (IS_ERR(mux_clk)) {
kfree(frac);
- return clk;
+ return mux_clk;
}
rockchip_clk_add_lookup(ctx, mux_clk, child->id);
@@ -345,7 +346,7 @@
if (frac->mux_frac_idx >= 0) {
pr_debug("%s: found fractional parent in mux at pos %d\n",
__func__, frac->mux_frac_idx);
- ret = clk_notifier_register(clk, &frac->clk_nb);
+ ret = clk_notifier_register(hw->clk, &frac->clk_nb);
if (ret)
pr_err("%s: failed to register clock notifier for %s\n",
__func__, name);
@@ -355,7 +356,7 @@
}
}
- return clk;
+ return hw->clk;
}
static struct clk *rockchip_clk_register_factor_branch(const char *name,
@@ -364,7 +365,7 @@
int gate_offset, u8 gate_shift, u8 gate_flags,
unsigned long flags, spinlock_t *lock)
{
- struct clk *clk;
+ struct clk_hw *hw;
struct clk_gate *gate = NULL;
struct clk_fixed_factor *fix = NULL;
@@ -393,75 +394,22 @@
fix->mult = mult;
fix->div = div;
- clk = clk_register_composite(NULL, name, parent_names, num_parents,
- NULL, NULL,
- &fix->hw, &clk_fixed_factor_ops,
- &gate->hw, &clk_gate_ops, flags);
- if (IS_ERR(clk)) {
+ hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+ NULL, NULL,
+ &fix->hw, &clk_fixed_factor_ops,
+ &gate->hw, &clk_gate_ops, flags);
+ if (IS_ERR(hw)) {
kfree(fix);
kfree(gate);
+ return ERR_CAST(hw);
}
- return clk;
+ return hw->clk;
}
-static struct clk *rockchip_clk_register_composite_brother_branch(
- struct rockchip_clk_provider *ctx, const char *name,
- const char *const *parent_names, u8 num_parents,
- void __iomem *base, int muxdiv_offset, u8 mux_shift,
- u8 mux_width, u8 mux_flags, u32 *mux_table,
- int div_offset, u8 div_shift, u8 div_width, u8 div_flags,
- struct clk_div_table *div_table, int gate_offset,
- u8 gate_shift, u8 gate_flags, unsigned long flags,
- struct rockchip_clk_branch *brother, spinlock_t *lock)
-{
- struct clk *clk, *brother_clk;
- struct clk_composite *composite, *brother_composite;
- struct clk_hw *hw, *brother_hw;
-
- if (brother && brother->branch_type != branch_half_divider) {
- pr_err("%s: composite brother for %s can only be a halfdiv\n",
- __func__, name);
- return ERR_PTR(-EINVAL);
- }
-
- clk = rockchip_clk_register_branch(name, parent_names, num_parents,
- base, muxdiv_offset, mux_shift,
- mux_width, mux_flags, mux_table,
- div_offset, div_shift, div_width,
- div_flags, div_table,
- gate_offset, gate_shift, gate_flags,
- flags, lock);
- if (IS_ERR(clk))
- return clk;
-
- brother_clk = rockchip_clk_register_halfdiv(brother->name,
- brother->parent_names, brother->num_parents,
- base, brother->muxdiv_offset,
- brother->mux_shift, brother->mux_width,
- brother->mux_flags, brother->div_offset,
- brother->div_shift, brother->div_width,
- brother->div_flags, brother->gate_offset,
- brother->gate_shift, brother->gate_flags,
- flags, lock);
- if (IS_ERR(brother_clk))
- return brother_clk;
- rockchip_clk_add_lookup(ctx, brother_clk, brother->id);
-
- hw = __clk_get_hw(clk);
- brother_hw = __clk_get_hw(brother_clk);
- if (hw && brother_hw) {
- composite = to_clk_composite(hw);
- brother_composite = to_clk_composite(brother_hw);
- composite->brother_hw = brother_hw;
- brother_composite->brother_hw = hw;
- }
-
- return clk;
-}
-
-struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np,
- void __iomem *base, unsigned long nr_clks)
+struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
+ void __iomem *base,
+ unsigned long nr_clks)
{
struct rockchip_clk_provider *ctx;
struct clk **clk_table;
@@ -489,20 +437,26 @@
ctx->pmugrf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
"rockchip,pmugrf");
+#ifdef MODULE
+ hlist_add_head(&ctx->list_node, &clk_ctx_list);
+#endif
+
return ctx;
err_free:
kfree(ctx);
return ERR_PTR(-ENOMEM);
}
+EXPORT_SYMBOL_GPL(rockchip_clk_init);
-void __init rockchip_clk_of_add_provider(struct device_node *np,
- struct rockchip_clk_provider *ctx)
+void rockchip_clk_of_add_provider(struct device_node *np,
+ struct rockchip_clk_provider *ctx)
{
if (of_clk_add_provider(np, of_clk_src_onecell_get,
&ctx->clk_data))
pr_err("%s: could not register clk provider\n", __func__);
}
+EXPORT_SYMBOL_GPL(rockchip_clk_of_add_provider);
void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
struct clk *clk, unsigned int id)
@@ -510,8 +464,9 @@
if (ctx->clk_data.clks && id)
ctx->clk_data.clks[id] = clk;
}
+EXPORT_SYMBOL_GPL(rockchip_clk_add_lookup);
-void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
+void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
struct rockchip_pll_clock *list,
unsigned int nr_pll, int grf_lock_offset)
{
@@ -534,11 +489,11 @@
rockchip_clk_add_lookup(ctx, clk, list->id);
}
}
+EXPORT_SYMBOL_GPL(rockchip_clk_register_plls);
-void __init rockchip_clk_register_branches(
- struct rockchip_clk_provider *ctx,
- struct rockchip_clk_branch *list,
- unsigned int nr_clk)
+void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
+ struct rockchip_clk_branch *list,
+ unsigned int nr_clk)
{
struct clk *clk = NULL;
unsigned int idx;
@@ -604,7 +559,7 @@
list->div_flags,
list->gate_offset, list->gate_shift,
list->gate_flags, flags, list->child,
- list->max_prate, &ctx->lock);
+ &ctx->lock);
break;
case branch_half_divider:
clk = rockchip_clk_register_halfdiv(list->name,
@@ -618,8 +573,15 @@
flags, &ctx->lock);
break;
case branch_gate:
- if (!(list->gate_flags & CLK_GATE_NO_SET_RATE))
- flags |= CLK_SET_RATE_PARENT;
+ flags |= CLK_SET_RATE_PARENT;
+
+ clk = clk_register_gate(NULL, list->name,
+ list->parent_names[0], flags,
+ ctx->reg_base + list->gate_offset,
+ list->gate_shift, list->gate_flags, &ctx->lock);
+ break;
+ case branch_gate_no_set_rate:
+ flags &= ~CLK_SET_RATE_PARENT;
clk = clk_register_gate(NULL, list->name,
list->parent_names[0], flags,
@@ -637,19 +599,6 @@
list->div_flags, list->div_table,
list->gate_offset, list->gate_shift,
list->gate_flags, flags, &ctx->lock);
- break;
- case branch_composite_brother:
- clk = rockchip_clk_register_composite_brother_branch(
- ctx, list->name, list->parent_names,
- list->num_parents, ctx->reg_base,
- list->muxdiv_offset, list->mux_shift,
- list->mux_width, list->mux_flags,
- list->mux_table, list->div_offset,
- list->div_shift, list->div_width,
- list->div_flags, list->div_table,
- list->gate_offset, list->gate_shift,
- list->gate_flags, flags, list->child,
- &ctx->lock);
break;
case branch_mmc:
clk = rockchip_clk_register_mmc(
@@ -685,18 +634,6 @@
list->div_width, list->div_flags,
ctx->reg_base);
break;
- case branch_dclk_divider:
-#ifdef CONFIG_ROCKCHIP_DCLK_DIV
- clk = rockchip_clk_register_dclk_branch(list->name,
- list->parent_names, list->num_parents,
- ctx->reg_base, list->muxdiv_offset, list->mux_shift,
- list->mux_width, list->mux_flags,
- list->div_offset, list->div_shift, list->div_width,
- list->div_flags, list->div_table,
- list->gate_offset, list->gate_shift,
- list->gate_flags, flags, list->max_prate, &ctx->lock);
-#endif
- break;
}
/* none of the cases above matched */
@@ -715,18 +652,21 @@
rockchip_clk_add_lookup(ctx, clk, list->id);
}
}
+EXPORT_SYMBOL_GPL(rockchip_clk_register_branches);
-void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
- unsigned int lookup_id,
- const char *name, const char *const *parent_names,
- u8 num_parents,
- const struct rockchip_cpuclk_reg_data *reg_data,
- const struct rockchip_cpuclk_rate_table *rates,
- int nrates)
+void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
+ unsigned int lookup_id,
+ const char *name,
+ u8 num_parents,
+ struct clk *parent, struct clk *alt_parent,
+ const struct rockchip_cpuclk_reg_data *reg_data,
+ const struct rockchip_cpuclk_rate_table *rates,
+ int nrates)
{
struct clk *clk;
- clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents,
+ clk = rockchip_clk_register_cpuclk(name, num_parents,
+ parent, alt_parent,
reg_data, rates, nrates,
ctx->reg_base, &ctx->lock);
if (IS_ERR(clk)) {
@@ -737,20 +677,31 @@
rockchip_clk_add_lookup(ctx, clk, lookup_id);
}
+EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk);
-void __init rockchip_clk_protect_critical(const char *const clocks[],
- int nclocks)
+void rockchip_clk_register_armclk_v2(struct rockchip_clk_provider *ctx,
+ struct rockchip_clk_branch *list,
+ const struct rockchip_cpuclk_rate_table *rates,
+ int nrates)
{
- int i;
+ struct clk *clk;
- /* Protect the clocks that needs to stay on */
- for (i = 0; i < nclocks; i++) {
- struct clk *clk = __clk_lookup(clocks[i]);
-
- if (clk)
- clk_prepare_enable(clk);
+ clk = rockchip_clk_register_cpuclk_v2(list->name, list->parent_names,
+ list->num_parents, ctx->reg_base,
+ list->muxdiv_offset, list->mux_shift,
+ list->mux_width, list->mux_flags,
+ list->div_offset, list->div_shift,
+ list->div_width, list->div_flags,
+ list->flags, &ctx->lock, rates, nrates);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s: %ld\n",
+ __func__, list->name, PTR_ERR(clk));
+ return;
}
+
+ rockchip_clk_add_lookup(ctx, clk, list->id);
}
+EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk_v2);
void (*rk_dump_cru)(void);
EXPORT_SYMBOL(rk_dump_cru);
@@ -785,10 +736,10 @@
.priority = 128,
};
-void __init
+void
rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
- unsigned int reg,
- void (*cb)(void))
+ unsigned int reg,
+ void (*cb)(void))
{
int ret;
@@ -802,3 +753,83 @@
atomic_notifier_chain_register(&panic_notifier_list,
&rk_clk_panic_block);
}
+EXPORT_SYMBOL_GPL(rockchip_register_restart_notifier);
+
+#ifdef MODULE
+static struct clk **protect_clocks;
+static unsigned int protect_nclocks;
+
+int rockchip_clk_protect(struct rockchip_clk_provider *ctx,
+ unsigned int *clocks, unsigned int nclocks)
+{
+ struct clk *clk = NULL;
+ int i = 0;
+
+ if (protect_clocks || !ctx || !clocks || !ctx->clk_data.clks)
+ return 0;
+
+ protect_clocks = kcalloc(nclocks, sizeof(void *), GFP_KERNEL);
+ if (!protect_clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < nclocks; i++) {
+ if (clocks[i] >= ctx->clk_data.clk_num) {
+ pr_err("%s: invalid clock id %u\n", __func__, clocks[i]);
+ continue;
+ }
+ clk = ctx->clk_data.clks[clocks[i]];
+ if (clk) {
+ clk_prepare_enable(clk);
+ protect_clocks[i] = clk;
+ }
+ }
+ protect_nclocks = nclocks;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_clk_protect);
+
+void rockchip_clk_unprotect(void)
+{
+ int i = 0;
+
+ if (!protect_clocks || !protect_nclocks)
+ return;
+
+ for (i = 0; i < protect_nclocks; i++) {
+ if (protect_clocks[i])
+ clk_disable_unprepare(protect_clocks[i]);
+ }
+ protect_nclocks = 0;
+ kfree(protect_clocks);
+ protect_clocks = NULL;
+
+}
+EXPORT_SYMBOL_GPL(rockchip_clk_unprotect);
+
+void rockchip_clk_disable_unused(void)
+{
+ struct rockchip_clk_provider *ctx;
+ struct clk *clk;
+ struct clk_hw *hw;
+ int i = 0, flag = 0;
+
+ hlist_for_each_entry(ctx, &clk_ctx_list, list_node) {
+ for (i = 0; i < ctx->clk_data.clk_num; i++) {
+ clk = ctx->clk_data.clks[i];
+ if (clk && !IS_ERR(clk)) {
+ hw = __clk_get_hw(clk);
+ if (hw)
+ flag = clk_hw_get_flags(hw);
+ if (flag & CLK_IGNORE_UNUSED)
+ continue;
+ if (flag & CLK_IS_CRITICAL)
+ continue;
+ clk_prepare_enable(clk);
+ clk_disable_unprepare(clk);
+ }
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(rockchip_clk_disable_unused);
+#endif /* MODULE */
--
Gitblit v1.6.2