CLK: ARC: HSDK: avoid code duplication
hsdk_axi_clk_cfg and hsdk_tun_clk_cfg clock divider structures
and functions for their processing are almost the same so
merge them to avoid code duplication.
Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c
index 3035c5f..a51e780 100644
--- a/drivers/clk/clk-hsdk-cgu.c
+++ b/drivers/clk/clk-hsdk-cgu.c
@@ -126,45 +126,31 @@
#define PARENT_RATE_27 27000000 /* fixed clock - xtal */
#define CGU_MAX_CLOCKS 27
-#define CGU_SYS_CLOCKS 16
-#define MAX_AXI_CLOCKS 4
+#define MAX_FREQ_VARIATIONS 6
-#define CGU_TUN_CLOCKS 4
-#define MAX_TUN_CLOCKS 6
-
-struct hsdk_tun_idiv_cfg {
+struct hsdk_idiv_cfg {
u32 oft;
- u8 val[MAX_TUN_CLOCKS];
+ u8 val[MAX_FREQ_VARIATIONS];
};
-struct hsdk_tun_clk_cfg {
- const u32 clk_rate[MAX_TUN_CLOCKS];
- const u32 pll_rate[MAX_TUN_CLOCKS];
- const struct hsdk_tun_idiv_cfg idiv[CGU_TUN_CLOCKS];
+struct hsdk_div_full_cfg {
+ const u32 clk_rate[MAX_FREQ_VARIATIONS];
+ const u32 pll_rate[MAX_FREQ_VARIATIONS];
+ const struct hsdk_idiv_cfg idiv[];
};
-static const struct hsdk_tun_clk_cfg tun_clk_cfg = {
+static const struct hsdk_div_full_cfg tun_clk_cfg = {
{ 25000000, 50000000, 75000000, 100000000, 125000000, 150000000 },
{ 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
{ CGU_TUN_IDIV_TUN, { 24, 12, 8, 6, 6, 4 } },
{ CGU_TUN_IDIV_ROM, { 4, 4, 4, 4, 5, 4 } },
{ CGU_TUN_IDIV_PWM, { 8, 8, 8, 8, 10, 8 } },
- { CGU_TUN_IDIV_TIMER, { 12, 12, 12, 12, 15, 12 } }
+ { CGU_TUN_IDIV_TIMER, { 12, 12, 12, 12, 15, 12 } },
+ { /* last one */ }
}
};
-struct hsdk_sys_idiv_cfg {
- u32 oft;
- u8 val[MAX_AXI_CLOCKS];
-};
-
-struct hsdk_axi_clk_cfg {
- const u32 clk_rate[MAX_AXI_CLOCKS];
- const u32 pll_rate[MAX_AXI_CLOCKS];
- const struct hsdk_sys_idiv_cfg idiv[CGU_SYS_CLOCKS];
-};
-
-static const struct hsdk_axi_clk_cfg axi_clk_cfg = {
+static const struct hsdk_div_full_cfg axi_clk_cfg = {
{ 200000000, 400000000, 600000000, 800000000 },
{ 800000000, 800000000, 600000000, 800000000 }, {
{ CGU_SYS_IDIV_APB, { 4, 4, 3, 4 } }, /* APB */
@@ -182,7 +168,8 @@
{ CGU_SYS_IDIV_SPI_REF, { 24, 24, 18, 24 } }, /* SPI-REF */
{ CGU_SYS_IDIV_I2C_REF, { 4, 4, 3, 4 } }, /* I2C-REF */
{ CGU_SYS_IDIV_UART_REF, { 24, 24, 18, 24 } }, /* UART-REF */
- { CGU_SYS_IDIV_EBI_REF, { 16, 16, 12, 16 } } /* EBI-REF */
+ { CGU_SYS_IDIV_EBI_REF, { 16, 16, 12, 16 } }, /* EBI-REF */
+ { /* last one */ }
}
};
@@ -546,8 +533,13 @@
return ret;
}
-/* Special behavior: wen we set this clock we set both idiv and pll and all pll dividers */
-static ulong axi_clk_set(struct clk *sclk, ulong rate)
+/*
+ * Special behavior:
+ * when we set these clocks we set both PLL and all idiv dividers related to
+ * this PLL domain.
+ */
+static ulong common_div_clk_set(struct clk *sclk, ulong rate,
+ const struct hsdk_div_full_cfg *cfg)
{
struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
ulong pll_rate;
@@ -556,71 +548,47 @@
pll_rate = pll_get(sclk);
- for (i = 0; i < MAX_AXI_CLOCKS; i++) {
- if (axi_clk_cfg.clk_rate[i] == rate) {
+ for (i = 0; i < MAX_FREQ_VARIATIONS; i++) {
+ /* unused freq variations are filled with 0 */
+ if (!cfg->clk_rate[i])
+ break;
+
+ if (cfg->clk_rate[i] == rate) {
freq_idx = i;
break;
}
}
if (freq_idx < 0) {
- pr_err("axi clk: invalid rate=%ld Hz\n", rate);
+ pr_err("clk: invalid rate=%ld Hz\n", rate);
return -EINVAL;
}
/* configure PLL before dividers */
- if (axi_clk_cfg.pll_rate[freq_idx] < pll_rate)
- ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
+ if (cfg->pll_rate[freq_idx] < pll_rate)
+ ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
/* configure SYS dividers */
- for (i = 0; i < CGU_SYS_CLOCKS; i++) {
- clk->idiv_regs = clk->cgu_regs + axi_clk_cfg.idiv[i].oft;
- hsdk_idiv_write(clk, axi_clk_cfg.idiv[i].val[freq_idx]);
+ for (i = 0; cfg->idiv[i].oft != 0; i++) {
+ clk->idiv_regs = clk->cgu_regs + cfg->idiv[i].oft;
+ hsdk_idiv_write(clk, cfg->idiv[i].val[freq_idx]);
}
/* configure PLL after dividers */
- if (axi_clk_cfg.pll_rate[freq_idx] >= pll_rate)
- ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
+ if (cfg->pll_rate[freq_idx] >= pll_rate)
+ ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
return ret;
}
-static ulong tun_clk_set(struct clk *sclk, ulong rate)
+static ulong axi_clk_set(struct clk *sclk, ulong rate)
{
- struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
- ulong pll_rate;
- int i, freq_idx = -1;
- ulong ret = 0;
-
- pll_rate = pll_get(sclk);
-
- for (i = 0; i < MAX_TUN_CLOCKS; i++) {
- if (tun_clk_cfg.clk_rate[i] == rate) {
- freq_idx = i;
- break;
- }
- }
-
- if (freq_idx < 0) {
- pr_err("tun clk: invalid rate=%ld Hz\n", rate);
- return -EINVAL;
- }
-
- /* configure PLL before dividers */
- if (tun_clk_cfg.pll_rate[freq_idx] < pll_rate)
- ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
-
- /* configure SYS dividers */
- for (i = 0; i < CGU_TUN_CLOCKS; i++) {
- clk->idiv_regs = clk->cgu_regs + tun_clk_cfg.idiv[i].oft;
- hsdk_idiv_write(clk, tun_clk_cfg.idiv[i].val[freq_idx]);
- }
-
- /* configure PLL after dividers */
- if (tun_clk_cfg.pll_rate[freq_idx] >= pll_rate)
- ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
+ return common_div_clk_set(sclk, rate, &axi_clk_cfg);
+}
- return ret;
+static ulong tun_clk_set(struct clk *sclk, ulong rate)
+{
+ return common_div_clk_set(sclk, rate, &tun_clk_cfg);
}
static ulong idiv_set(struct clk *sclk, ulong rate)