[PATCH v14 4/5] clk: sophgo: Add SG2042 clock driver

Stephen Boyd sboyd at kernel.org
Mon Apr 22 17:47:36 PDT 2024


Quoting Chen Wang (2024-04-15 00:23:27)
> diff --git a/drivers/clk/sophgo/clk-sophgo-sg2042.c b/drivers/clk/sophgo/clk-sophgo-sg2042.c
> new file mode 100644
> index 000000000000..0bcfaab52f51
> --- /dev/null
> +++ b/drivers/clk/sophgo/clk-sophgo-sg2042.c
> @@ -0,0 +1,1645 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Sophgo SG2042 Clock Generator Driver
> + *
> + * Copyright (C) 2024 Sophgo Technology Inc. All rights reserved.
> + */
> +
> +#include <asm/div64.h>

asm goes after linux includes...

> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/platform_device.h>

here.

> +
> +/*
> + * The clock of SG2042 is composed of three parts.
> + * The registers of these three parts of the clock are scattered in three
> + * different memory address spaces:
> + * - pll clocks
> + * - gate clocks for RP subsystem
> + * - div/mux, and gate clocks working for other subsystem than RP subsystem
> + */
> +#include <dt-bindings/clock/sophgo,sg2042-pll.h>
> +#include <dt-bindings/clock/sophgo,sg2042-rpgate.h>
> +#include <dt-bindings/clock/sophgo,sg2042-clkgen.h>
> +
> +/* Registers defined in SYS_CTRL */
> +#define R_PLL_BEGIN            0xC0
[...]
> +
> +#define SG2042_PLL(_id, _name, _parent_name, _r_stat, _r_enable, _r_ctrl, _shift) \
> +       {                                                               \
> +               .hw.init = CLK_HW_INIT(                                 \
> +                               _name,                                  \
> +                               _parent_name,                           \

This still uses a string. Please convert all parents described by
strings to use clk_parent_data or clk_hw directly.

> +                               &sg2042_clk_pll_ops,                    \
> +                               CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE),\
> +               .id = _id,                                              \
> +               .offset_ctrl = _r_ctrl,                                 \
> +               .offset_status = _r_stat,                               \
> +               .offset_enable = _r_enable,                             \
> +               .shift_status_lock = 8 + (_shift),                      \
> +               .shift_status_updating = _shift,                        \
[...]
> + * "clk_div_ddr01_1" is the name of Clock divider 1 control of DDR01, and
> + * "clk_gate_ddr01_div1" is the gate clock in front of the "clk_div_ddr01_1",
> + * they are both controlled by register CLKDIVREG28;
> + * While for register value of mux selection, use Clock Select for DDR01’s clock
> + * as example, see CLKSELREG0, bit[2].
> + * 1: Select in_dpll0_clk as clock source, correspondng to the parent input
> + *    source from "clk_div_ddr01_0".
> + * 0: Select in_fpll_clk as clock source, corresponding to the parent input
> + *    source from "clk_div_ddr01_1".
> + * So we need a table to define the array of register values corresponding to
> + * the parent index and tell CCF about this when registering mux clock.
> + */
> +static const u32 sg2042_mux_table[] = {1, 0};
> +
> +static const struct clk_parent_data clk_mux_ddr01_p[] = {
> +       { .hw = &sg2042_div_clks[0].hw },
> +       { .hw = &sg2042_div_clks[1].hw },

Just use struct clk_init_data::parent_hws for this if you only have a
clk_hw pointer for every element of the parent array.

> +};
> +
> +static const struct clk_parent_data clk_mux_ddr23_p[] = {
> +       { .hw = &sg2042_div_clks[2].hw },
> +       { .hw = &sg2042_div_clks[3].hw },
> +};
> +
[...]
> +
> +static int sg2042_pll_probe(struct platform_device *pdev)
> +{
> +       struct sg2042_clk_data *clk_data = NULL;
> +       int i, ret = 0;
> +       int num_clks = 0;
> +
> +       num_clks = ARRAY_SIZE(sg2042_pll_clks);
> +
> +       ret = sg2042_init_clkdata(pdev, num_clks, &clk_data);
> +       if (ret < 0)
> +               goto error_out;
> +
> +       ret = sg2042_clk_register_plls(&pdev->dev, clk_data, sg2042_pll_clks,
> +                                      num_clks);
> +       if (ret)
> +               goto cleanup;
> +
> +       return devm_of_clk_add_hw_provider(&pdev->dev,
> +                                          of_clk_hw_onecell_get,
> +                                          &clk_data->onecell_data);
> +
> +cleanup:
> +       for (i = 0; i < num_clks; i++) {
> +               if (clk_data->onecell_data.hws[i])
> +                       clk_hw_unregister(clk_data->onecell_data.hws[i]);

This should be unnecessary if devm is used throughout.

> +       }
> +
> +error_out:
> +       pr_err("%s failed error number %d\n", __func__, ret);
> +       return ret;

Just do this part in the one place the goto is. These two comments apply
to all probes.



More information about the linux-riscv mailing list