diff options
Diffstat (limited to 'drivers/clk/st/clkgen-fsyn.c')
| -rw-r--r-- | drivers/clk/st/clkgen-fsyn.c | 181 |
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, ¶ms)) - return rate; + if (clk_fs660c32_vco_get_params(req->best_parent_rate, req->rate, ¶ms)) + return 0; - clk_fs660c32_vco_get_rate(*prate, ¶ms, &rate); + clk_fs660c32_vco_get_rate(req->best_parent_rate, ¶ms, &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, ¶ms); + req->rate = quadfs_find_best_rate(hw, req->rate, + req->best_parent_rate, ¶ms); 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); |
