summaryrefslogtreecommitdiff
path: root/drivers/clk/st/clkgen-fsyn.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/st/clkgen-fsyn.c')
-rw-r--r--drivers/clk/st/clkgen-fsyn.c181
1 files changed, 139 insertions, 42 deletions
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
index 946ceb14dbf7..e06e7e5cc1a5 100644
--- a/drivers/clk/st/clkgen-fsyn.c
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 STMicroelectronics R&D Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
/*
@@ -70,8 +66,17 @@ struct clkgen_quadfs_data {
unsigned long *);
};
+struct clkgen_clk_out {
+ const char *name;
+ unsigned long flags;
+};
+
+struct clkgen_quadfs_data_clks {
+ struct clkgen_quadfs_data *data;
+ const struct clkgen_clk_out *outputs;
+};
+
static const struct clk_ops st_quadfs_pll_c32_ops;
-static const struct clk_ops st_quadfs_fs660c32_ops;
static int clk_fs660c32_dig_get_params(unsigned long input,
unsigned long output, struct stm_fs *fs);
@@ -120,6 +125,18 @@ static const struct clkgen_quadfs_data st_fs660c32_C = {
.get_rate = clk_fs660c32_dig_get_rate,
};
+static const struct clkgen_clk_out st_fs660c32_C_clks[] = {
+ { .name = "clk-s-c0-fs0-ch0", },
+ { .name = "clk-s-c0-fs0-ch1", },
+ { .name = "clk-s-c0-fs0-ch2", },
+ { .name = "clk-s-c0-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_C_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_C,
+ .outputs = st_fs660c32_C_clks,
+};
+
static const struct clkgen_quadfs_data st_fs660c32_D = {
.nrst_present = true,
.nrst = { CLKGEN_FIELD(0x2a0, 0x1, 0),
@@ -161,6 +178,46 @@ static const struct clkgen_quadfs_data st_fs660c32_D = {
.get_params = clk_fs660c32_dig_get_params,
.get_rate = clk_fs660c32_dig_get_rate,};
+static const struct clkgen_quadfs_data_clks st_fs660c32_D_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+};
+
+static const struct clkgen_clk_out st_fs660c32_D0_clks[] = {
+ { .name = "clk-s-d0-fs0-ch0", },
+ { .name = "clk-s-d0-fs0-ch1", },
+ { .name = "clk-s-d0-fs0-ch2", },
+ { .name = "clk-s-d0-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_D0_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+ .outputs = st_fs660c32_D0_clks,
+};
+
+static const struct clkgen_clk_out st_fs660c32_D2_clks[] = {
+ { .name = "clk-s-d2-fs0-ch0", },
+ { .name = "clk-s-d2-fs0-ch1", },
+ { .name = "clk-s-d2-fs0-ch2", },
+ { .name = "clk-s-d2-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_D2_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+ .outputs = st_fs660c32_D2_clks,
+};
+
+static const struct clkgen_clk_out st_fs660c32_D3_clks[] = {
+ { .name = "clk-s-d3-fs0-ch0", },
+ { .name = "clk-s-d3-fs0-ch1", },
+ { .name = "clk-s-d3-fs0-ch2", },
+ { .name = "clk-s-d3-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_D3_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+ .outputs = st_fs660c32_D3_clks,
+};
+
/**
* DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor
*
@@ -177,10 +234,10 @@ static const struct clkgen_quadfs_data st_fs660c32_D = {
* ST quad channel frequency synthesizer block
*
* @hw: handle between common and hardware-specific interfaces.
- * @ndiv: regmap field for the ndiv control.
* @regs_base: base address of the configuration registers.
* @lock: spinlock.
- *
+ * @data: local driver data
+ * @ndiv: regmap field for the ndiv control.
*/
struct st_clk_quadfs_pll {
struct clk_hw hw;
@@ -318,22 +375,21 @@ static int clk_fs660c32_vco_get_params(unsigned long input,
return 0;
}
-static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *prate)
+static int quadfs_pll_fs660c32_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct stm_fs params;
- if (clk_fs660c32_vco_get_params(*prate, rate, &params))
- return rate;
+ if (clk_fs660c32_vco_get_params(req->best_parent_rate, req->rate, &params))
+ return 0;
- clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+ clk_fs660c32_vco_get_rate(req->best_parent_rate, &params, &req->rate);
pr_debug("%s: %s new rate %ld [ndiv=%u]\n",
__func__, clk_hw_get_name(hw),
- rate, (unsigned int)params.ndiv);
+ req->rate, (unsigned int)params.ndiv);
- return rate;
+ return 0;
}
static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -379,7 +435,7 @@ static const struct clk_ops st_quadfs_pll_c32_ops = {
.disable = quadfs_pll_disable,
.is_enabled = quadfs_pll_is_enabled,
.recalc_rate = quadfs_pll_fs660c32_recalc_rate,
- .round_rate = quadfs_pll_fs660c32_round_rate,
+ .determine_rate = quadfs_pll_fs660c32_determine_rate,
.set_rate = quadfs_pll_fs660c32_set_rate,
};
@@ -431,7 +487,7 @@ static struct clk * __init st_clk_register_quadfs_pll(
* parent - fixed parent. No clk_set_parent support
*/
-/**
+/*
* struct st_clk_quadfs_fsynth - One clock output from a four channel digital
* frequency synthesizer (fsynth) block.
*
@@ -757,19 +813,21 @@ static unsigned long quadfs_recalc_rate(struct clk_hw *hw,
return rate;
}
-static long quadfs_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int quadfs_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct stm_fs params;
- rate = quadfs_find_best_rate(hw, rate, *prate, &params);
+ req->rate = quadfs_find_best_rate(hw, req->rate,
+ req->best_parent_rate, &params);
pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
__func__, clk_hw_get_name(hw),
- rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv,
- (unsigned int)params.pe, (unsigned int)params.nsdiv);
+ req->rate, (unsigned int)params.sdiv,
+ (unsigned int)params.mdiv,
+ (unsigned int)params.pe, (unsigned int)params.nsdiv);
- return rate;
+ return 0;
}
@@ -795,7 +853,6 @@ static int quadfs_set_rate(struct clk_hw *hw, unsigned long rate,
struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
struct stm_fs params;
long hwrate;
- int uninitialized_var(i);
if (!rate || !parent_rate)
return -EINVAL;
@@ -817,7 +874,7 @@ static const struct clk_ops st_quadfs_ops = {
.enable = quadfs_fsynth_enable,
.disable = quadfs_fsynth_disable,
.is_enabled = quadfs_fsynth_is_enabled,
- .round_rate = quadfs_round_rate,
+ .determine_rate = quadfs_determine_rate,
.set_rate = quadfs_set_rate,
.recalc_rate = quadfs_recalc_rate,
};
@@ -863,7 +920,7 @@ static struct clk * __init st_clk_register_quadfs_fsynth(
static void __init st_of_create_quadfs_fsynths(
struct device_node *np, const char *pll_name,
- struct clkgen_quadfs_data *quadfs, void __iomem *reg,
+ struct clkgen_quadfs_data_clks *quadfs, void __iomem *reg,
spinlock_t *lock)
{
struct clk_onecell_data *clk_data;
@@ -887,9 +944,15 @@ static void __init st_of_create_quadfs_fsynths(
const char *clk_name;
unsigned long flags = 0;
- if (of_property_read_string_index(np, "clock-output-names",
- fschan, &clk_name)) {
- break;
+ if (quadfs->outputs) {
+ clk_name = quadfs->outputs[fschan].name;
+ flags = quadfs->outputs[fschan].flags;
+ } else {
+ if (of_property_read_string_index(np,
+ "clock-output-names",
+ fschan, &clk_name))
+ break;
+ of_clk_detect_critical(np, fschan, &flags);
}
/*
@@ -898,10 +961,8 @@ static void __init st_of_create_quadfs_fsynths(
if (*clk_name == '\0')
continue;
- of_clk_detect_critical(np, fschan, &flags);
-
clk = st_clk_register_quadfs_fsynth(clk_name, pll_name,
- quadfs, reg, fschan,
+ quadfs->data, reg, fschan,
flags, lock);
/*
@@ -921,16 +982,28 @@ static void __init st_of_create_quadfs_fsynths(
}
static void __init st_of_quadfs_setup(struct device_node *np,
- struct clkgen_quadfs_data *data)
+ struct clkgen_quadfs_data_clks *datac)
{
struct clk *clk;
const char *pll_name, *clk_parent_name;
void __iomem *reg;
spinlock_t *lock;
+ struct device_node *parent_np;
+ /*
+ * First check for reg property within the node to keep backward
+ * compatibility, then if reg doesn't exist look at the parent node
+ */
reg = of_iomap(np, 0);
- if (!reg)
- return;
+ if (!reg) {
+ parent_np = of_get_parent(np);
+ reg = of_iomap(parent_np, 0);
+ of_node_put(parent_np);
+ if (!reg) {
+ pr_err("%s: Failed to get base address\n", __func__);
+ return;
+ }
+ }
clk_parent_name = of_clk_get_parent_name(np, 0);
if (!clk_parent_name)
@@ -946,17 +1019,18 @@ static void __init st_of_quadfs_setup(struct device_node *np,
spin_lock_init(lock);
- clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, data,
+ clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, datac->data,
reg, lock);
- if (IS_ERR(clk))
+ if (IS_ERR(clk)) {
+ kfree(lock);
goto err_exit;
- else
+ } else
pr_debug("%s: parent %s rate %u\n",
__clk_get_name(clk),
__clk_get_name(clk_get_parent(clk)),
(unsigned int)clk_get_rate(clk));
- st_of_create_quadfs_fsynths(np, pll_name, data, reg, lock);
+ st_of_create_quadfs_fsynths(np, pll_name, datac, reg, lock);
err_exit:
kfree(pll_name); /* No longer need local copy of the PLL name */
@@ -964,12 +1038,35 @@ err_exit:
static void __init st_of_quadfs660C_setup(struct device_node *np)
{
- st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_C);
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_C_data);
}
CLK_OF_DECLARE(quadfs660C, "st,quadfs-pll", st_of_quadfs660C_setup);
static void __init st_of_quadfs660D_setup(struct device_node *np)
{
- st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_D);
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D_data);
}
CLK_OF_DECLARE(quadfs660D, "st,quadfs", st_of_quadfs660D_setup);
+
+static void __init st_of_quadfs660D0_setup(struct device_node *np)
+{
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D0_data);
+}
+CLK_OF_DECLARE(quadfs660D0, "st,quadfs-d0", st_of_quadfs660D0_setup);
+
+static void __init st_of_quadfs660D2_setup(struct device_node *np)
+{
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D2_data);
+}
+CLK_OF_DECLARE(quadfs660D2, "st,quadfs-d2", st_of_quadfs660D2_setup);
+
+static void __init st_of_quadfs660D3_setup(struct device_node *np)
+{
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D3_data);
+}
+CLK_OF_DECLARE(quadfs660D3, "st,quadfs-d3", st_of_quadfs660D3_setup);