[PATCH 06/14] staging: clocking-wizard: Swap CCF clock providers
Michal Simek
michal.simek at xilinx.com
Fri May 11 06:21:19 UTC 2018
On 7.5.2018 03:20, James Kelly wrote:
> Replace existing CCF clock providers with new clock provider that can
> be enhanced to meet our needs.
>
> AXI clock prepare/enable/disable/unprepare is now managed by regmap APIs.
>
> Unregistering of clk instances now handled by devm APIs.
>
> Drop warning that fractional ratios are not supported because it used
> undocumented register fields and it won't be needed anymore.
>
> Signed-off-by: James Kelly <jamespeterkelly at gmail.com>
> ---
> .../clocking-wizard/clk-xlnx-clock-wizard.c | 211 +++++++--------------
> 1 file changed, 71 insertions(+), 140 deletions(-)
>
> diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
> index ba9b1dc93d50..1dbeda92fb9a 100644
> --- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
> +++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
> @@ -76,24 +76,6 @@
> #define WZRD_CLKNAME_IN1 "clk_in1"
> #define WZRD_FLAG_MULTIPLY BIT(0)
>
> -#define WZRD_CLK_CFG_REG(n) (0x200 + 4 * (n))
> -
> -#define WZRD_CLKOUT0_FRAC_EN BIT(18)
> -#define WZRD_CLKFBOUT_FRAC_EN BIT(26)
> -
> -#define WZRD_CLKFBOUT_MULT_SHIFT 8
> -#define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT)
> -#define WZRD_DIVCLK_DIVIDE_SHIFT 0
> -#define WZRD_DIVCLK_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT)
> -#define WZRD_CLKOUT_DIVIDE_SHIFT 0
> -#define WZRD_CLKOUT_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT)
> -
> -enum clk_wzrd_int_clks {
> - wzrd_clk_mul_div,
> - wzrd_clk_mul,
> - wzrd_clk_int_max
> -};
> -
> enum clk_wzrd_clk {
> WZRD_CLK_DIV,
> WZRD_CLK_PLL,
> @@ -149,14 +131,13 @@ struct clk_wzrd_clk_data {
> container_of(_hw, struct clk_wzrd_clk_data, hw)
>
> /**
> - * struct clk_wzrd:
> - * @clk_data: Clock data
> + * struct clk_wzrd - Platform driver data for clocking wizard device
> + *
> + * @clk_data: Clock data accessible to other devices via device tree
> * @nb: Notifier block
> - * @base: Memory base
> * @regmap: Register map for hardware
> * @clk_in1: Handle to input clock 'clk_in1'
> * @axi_clk: Handle to input clock 's_axi_aclk'
> - * @clks_internal: Internal clocks
> * @clkout: Output clocks
> * @speed_grade: Speed grade of the device
> * @suspended: Flag indicating power state of the device
> @@ -167,11 +148,9 @@ struct clk_wzrd_clk_data {
> struct clk_wzrd {
> struct clk_onecell_data clk_data;
> struct notifier_block nb;
> - void __iomem *base;
> struct regmap *regmap;
> struct clk *clk_in1;
> struct clk *axi_clk;
> - struct clk *clks_internal[wzrd_clk_int_max];
> struct clk *clkout[WZRD_NUM_OUTPUTS];
> unsigned int speed_grade;
> bool suspended;
> @@ -179,7 +158,6 @@ struct clk_wzrd {
> struct clk_wzrd_clk_data pll_data;
> struct clk_wzrd_clk_data clkout_data[0];
> };
> -
> #define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb)
>
> /* maximum frequencies for input/output clocks per speed grade */
> @@ -321,7 +299,6 @@ static int __maybe_unused clk_wzrd_suspend(struct device *dev)
> {
> struct clk_wzrd *cw = dev_get_drvdata(dev);
>
> - clk_disable_unprepare(cw->axi_clk);
> cw->suspended = true;
>
> return 0;
> @@ -329,15 +306,8 @@ static int __maybe_unused clk_wzrd_suspend(struct device *dev)
>
> static int __maybe_unused clk_wzrd_resume(struct device *dev)
> {
> - int ret;
> struct clk_wzrd *cw = dev_get_drvdata(dev);
>
> - ret = clk_prepare_enable(cw->axi_clk);
> - if (ret) {
> - dev_err(dev, "unable to enable s_axi_aclk\n");
> - return ret;
> - }
> -
> cw->suspended = false;
>
> return 0;
> @@ -348,17 +318,32 @@ static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend,
>
> static int clk_wzrd_get_device_tree_data(struct device *dev)
> {
> - int ret;
> - unsigned long rate;
> + int num_outputs, ret;
> struct clk_wzrd *cw;
> + struct device_node *node = dev->of_node;
> +
> + num_outputs = of_property_count_strings(node,
> + "clock-output-names");
> + if (num_outputs < 1) {
> + dev_err(dev, "No clock output names in device tree\n");
> + if (num_outputs < 0)
> + return num_outputs;
> + else
> + return -EINVAL;
> + }
> + if (num_outputs > WZRD_NUM_OUTPUTS) {
> + dev_warn(dev, "Too many clock output names in device tree\n");
> + num_outputs = WZRD_NUM_OUTPUTS;
> + }
>
> - cw = devm_kzalloc(dev, sizeof(*cw), GFP_KERNEL);
> + cw = devm_kzalloc(dev, sizeof(*cw) + num_outputs *
> + sizeof(struct clk_wzrd_clk_data), GFP_KERNEL);
> if (!cw)
> return -ENOMEM;
> dev_set_drvdata(dev, cw);
> + cw->clk_data.clk_num = num_outputs;
>
> - ret = of_property_read_u32(dev->of_node, "speed-grade",
> - &cw->speed_grade);
> + ret = of_property_read_u32(node, "speed-grade", &cw->speed_grade);
> if (!ret) {
> if (cw->speed_grade < 1 || cw->speed_grade > 3) {
> dev_warn(dev, "invalid speed grade '%d'\n",
> @@ -380,18 +365,12 @@ static int clk_wzrd_get_device_tree_data(struct device *dev)
> dev_err(dev, "Clock %s not found\n", WZRD_CLKNAME_AXI);
> return PTR_ERR(cw->axi_clk);
> }
> - ret = clk_prepare_enable(cw->axi_clk);
> + ret = clk_set_max_rate(cw->axi_clk, WZRD_ACLK_MAX_FREQ);
> if (ret) {
> - dev_err(dev, "enabling %s failed\n", WZRD_CLKNAME_AXI);
> + dev_err(dev, "Unable to set clock %s to valid range\n",
> + WZRD_CLKNAME_AXI);
> return ret;
> }
> - rate = clk_get_rate(cw->axi_clk);
> - if (rate > WZRD_ACLK_MAX_FREQ) {
> - dev_err(dev, "%s frequency (%lu) too high\n", WZRD_CLKNAME_AXI,
> - rate);
> - clk_disable_unprepare(cw->axi_clk);
> - return -EINVAL;
> - }
>
> return 0;
> }
> @@ -399,12 +378,18 @@ static int clk_wzrd_get_device_tree_data(struct device *dev)
> static int clk_wzrd_regmap_alloc(struct device *dev)
> {
> struct resource *mem;
> + void __iomem *base;
> struct clk_wzrd *cw = dev_get_drvdata(dev);
>
> mem = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
> - cw->base = devm_ioremap_resource(dev, mem);
> - if (IS_ERR(cw->base))
> - return PTR_ERR(cw->base);
> + base = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + cw->regmap = devm_regmap_init_mmio_clk(dev, WZRD_CLKNAME_AXI,
> + base, &clk_wzrd_regmap_config);
> + if (IS_ERR(cw->regmap))
> + return PTR_ERR(cw->regmap);
>
> return 0;
> }
> @@ -412,115 +397,68 @@ static int clk_wzrd_regmap_alloc(struct device *dev)
> static int clk_wzrd_register_ccf(struct device *dev)
> {
> int i, ret;
> - u32 reg;
> - const char *clk_name;
> + const char *clk_div_name;
> + const char *clk_pll_name;
> +
> struct clk_wzrd *cw = dev_get_drvdata(dev);
>
> - /* we don't support fractional div/mul yet */
> - reg = readl(cw->base + WZRD_CLK_CFG_REG(0)) &
> - WZRD_CLKFBOUT_FRAC_EN;
> - reg |= readl(cw->base + WZRD_CLK_CFG_REG(2)) &
> - WZRD_CLKOUT0_FRAC_EN;
> - if (reg)
> - dev_warn(dev, "fractional div/mul not supported\n");
> -
> - /* register div */
> - reg = (readl(cw->base + WZRD_CLK_CFG_REG(0)) &
> - WZRD_DIVCLK_DIVIDE_MASK) >> WZRD_DIVCLK_DIVIDE_SHIFT;
> - clk_name = kasprintf(GFP_KERNEL, "%s_mul_div", dev_name(dev));
> - if (!clk_name) {
> - ret = -ENOMEM;
> - goto err_disable_clk;
> - }
> - cw->clks_internal[wzrd_clk_mul_div] = clk_register_fixed_factor(
> - dev, clk_name,
> - __clk_get_name(cw->clk_in1),
> - 0, 1, reg);
> - kfree(clk_name);
> - if (IS_ERR(cw->clks_internal[wzrd_clk_mul_div])) {
> - dev_err(dev, "unable to register divider clock\n");
> - ret = PTR_ERR(cw->clks_internal[wzrd_clk_mul_div]);
> - goto err_disable_clk;
> - }
> + clk_div_name = kasprintf(GFP_KERNEL, "%s_div", dev_name(dev));
> + if (!clk_div_name)
> + return -ENOMEM;
> + ret = clk_wzrd_register_clk(dev, clk_div_name, WZRD_CLK_DIV, 0, 0);
> + if (ret)
> + goto err_free_div_name;
>
> - /* register multiplier */
> - reg = (readl(cw->base + WZRD_CLK_CFG_REG(0)) &
> - WZRD_CLKFBOUT_MULT_MASK) >> WZRD_CLKFBOUT_MULT_SHIFT;
> - clk_name = kasprintf(GFP_KERNEL, "%s_mul", dev_name(dev));
> - if (!clk_name) {
> + clk_pll_name = kasprintf(GFP_KERNEL, "%s_pll", dev_name(dev));
> + if (!clk_pll_name) {
> ret = -ENOMEM;
> - goto err_rm_int_clk;
> - }
> - cw->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor(
> - dev, clk_name,
> - __clk_get_name(cw->clks_internal[wzrd_clk_mul_div]),
> - 0, reg, 1);
> - if (IS_ERR(cw->clks_internal[wzrd_clk_mul])) {
> - dev_err(dev, "unable to register fixed-factor clock\n");
> - ret = PTR_ERR(cw->clks_internal[wzrd_clk_mul]);
> - goto err_rm_int_clk;
> + goto err_free_div_name;
> }
> + ret = clk_wzrd_register_clk(dev, clk_pll_name, WZRD_CLK_PLL, 0, 0);
> + if (ret)
> + goto err_free_pll_name;
>
> - /* register div per output */
> - for (i = WZRD_NUM_OUTPUTS - 1; i >= 0 ; i--) {
> + for (i = cw->clk_data.clk_num - 1; i >= 0 ; i--) {
> const char *clkout_name;
>
> if (of_property_read_string_index(dev->of_node,
> "clock-output-names", i,
> &clkout_name)) {
> - dev_err(dev,
> - "clock output name not specified\n");
> + dev_err(dev, "clock output %d name not specified\n", i);
> ret = -EINVAL;
> - goto err_rm_int_clks;
> + goto err_free_pll_name;
> }
> - reg = readl(cw->base + WZRD_CLK_CFG_REG(2) + i * 12);
> - reg &= WZRD_CLKOUT_DIVIDE_MASK;
> - reg >>= WZRD_CLKOUT_DIVIDE_SHIFT;
> - cw->clkout[i] = clk_register_fixed_factor(dev, clkout_name,
> - clk_name, 0, 1, reg);
> - if (IS_ERR(cw->clkout[i])) {
> - int j;
> -
> - for (j = i + 1; j < WZRD_NUM_OUTPUTS; j++)
> - clk_unregister(cw->clkout[j]);
> - dev_err(dev,
> - "unable to register divider clock\n");
> - ret = PTR_ERR(cw->clkout[i]);
> - goto err_rm_int_clks;
> - }
> - }
>
> - kfree(clk_name);
> + ret = clk_wzrd_register_clk(dev, clkout_name, WZRD_CLK_OUT,
> + i, 0);
> + if (ret)
> + goto err_free_pll_name;
> +
> + cw->clkout[i] = cw->clkout_data[i].hw.clk;
> + }
>
> cw->clk_data.clks = cw->clkout;
> - cw->clk_data.clk_num = ARRAY_SIZE(cw->clkout);
> of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
> &cw->clk_data);
>
> if (cw->speed_grade) {
> cw->nb.notifier_call = clk_wzrd_clk_notifier;
>
> - ret = clk_notifier_register(cw->clk_in1,
> - &cw->nb);
> - if (ret)
> - dev_warn(dev,
> - "unable to register clock notifier\n");
> + ret = clk_notifier_register(cw->clk_in1, &cw->nb);
> + if (ret)
> + dev_warn(dev, "Unable to register input clock notifier\n");
>
> ret = clk_notifier_register(cw->axi_clk, &cw->nb);
> - if (ret)
> - dev_warn(dev,
> - "unable to register clock notifier\n");
> + if (ret)
> + dev_warn(dev, "Unable to register AXI clock notifier\n");
> }
>
> - return 0;
> + ret = 0;
>
> -err_rm_int_clks:
> - clk_unregister(cw->clks_internal[1]);
> -err_rm_int_clk:
> - kfree(clk_name);
> - clk_unregister(cw->clks_internal[0]);
> -err_disable_clk:
> - clk_disable_unprepare(cw->axi_clk);
> +err_free_pll_name:
> + kfree(clk_pll_name);
> +err_free_div_name:
> + kfree(clk_div_name);
>
> return ret;
> }
> @@ -547,23 +485,15 @@ static int clk_wzrd_probe(struct platform_device *pdev)
>
> static int clk_wzrd_remove(struct platform_device *pdev)
> {
> - int i;
> struct clk_wzrd *cw = platform_get_drvdata(pdev);
>
> of_clk_del_provider(pdev->dev.of_node);
>
> - for (i = 0; i < WZRD_NUM_OUTPUTS; i++)
> - clk_unregister(cw->clkout[i]);
> - for (i = 0; i < wzrd_clk_int_max; i++)
> - clk_unregister(cw->clks_internal[i]);
> -
> if (cw->speed_grade) {
> clk_notifier_unregister(cw->axi_clk, &cw->nb);
> clk_notifier_unregister(cw->clk_in1, &cw->nb);
> }
>
> - clk_disable_unprepare(cw->axi_clk);
> -
> return 0;
> }
>
> @@ -577,6 +507,7 @@ static struct platform_driver clk_wzrd_driver = {
> .driver = {
> .name = "clk-wizard",
> .of_match_table = clk_wzrd_ids,
> + .owner = THIS_MODULE,
This is not needed and coccinelle check this.
drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c:510:3-8: No need
to set .owner here. The core will do it.
Also there is one more warning.
drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c:391:1-3:
WARNING: PTR_ERR_OR_ZERO can be used
Thanks,
Michal
More information about the devel
mailing list