On 06/21, Abhishek Sahu wrote: > The current ipq4019 clock driver registered the PLL clocks and > dividers as fixed clock. These fixed clock needs to be removed > from driver probe function and same need to be registered with > clock framework. These PLL clocks should be programmed only > once and the same are being programmed already by the boot > loader so the set rate operation is not required for these > clocks. Only the rate can be calculated by clock operations > in clock driver file so this patch adds the same. > > The PLL takes the reference clock from XO and generates the > intermediate VCO frequency. This VCO frequency will be divided > down by different PLL internal dividers. Some of the PLL > internal dividers are fixed while other are programmable. > > This patch does the following changes. > 1. Operation for calculating PLL intermediate VCO frequency by > reading the reference clock divider and feedback divider from > register. Since VCO frequency falls outside the limit of > unsigned long for IPQ4019, so this operation will return the > VCO frequency in KHz. > > 2. Operation for calculating the internal PLL divider clock > frequency. Clock Divider node should give either fixed > divider value or divider table(maps the register divider > value to actual divider value). > > 3. Adds and registers clock nodes for VCO(APPS DDR PLL and FE > PLL) and PLL internal dividers(SDCC, FEPLL 500 Mhz, FEPLL > 200 Mhz, FEPLL 125 Mhz, FEPLL 125 Mhz with delay, > programmable WCSS 2G and 5G). > > 4. Changes the regmap limit from 0x2DFFF to 0x2FFFF for > supporting the PLL registers read. > > 5. Changes the fixed clock name to have consistency in all > clock names > > Signed-off-by: Abhishek Sahu <absahu@xxxxxxxxxxxxxx> Thanks for fixing this up, just some minor things to fix. > diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c > index 3cd1af0..17ca6d3 100644 > --- a/drivers/clk/qcom/gcc-ipq4019.c > +++ b/drivers/clk/qcom/gcc-ipq4019.c > @@ -20,6 +20,11 @@ > #include <linux/clk-provider.h> > #include <linux/regmap.h> > #include <linux/reset-controller.h> > +#include <linux/clk.h> Is this include used? > +#include <linux/delay.h> Is this include used? > +#include <linux/bitops.h> > +#include <linux/math64.h> > +#include <asm/div64.h> Are both includes needed? > @@ -40,6 +55,20 @@ enum { > P_DDRPLLAPSS, > }; > > +struct clk_pll_vco { > + u32 fdbkdiv_shift; > + u32 fdbkdiv_width; > + struct clk_regmap_div cdiv; > +}; > + > +struct clk_pll_div { > + u32 fixed_div; > + const u8 *parent_map; > + struct clk_regmap_div cdiv; > + const struct clk_div_table *div_table; > + const struct freq_tbl *freq_tbl; > +}; > + > static struct parent_map gcc_xo_200_500_map[] = { > { P_XO, 0 }, > { P_FEPLL200, 1 }, > @@ -48,8 +77,8 @@ static struct parent_map gcc_xo_200_500_map[] = { > > static const char * const gcc_xo_200_500[] = { > "xo", > - "fepll200", > - "fepll500", > + "gcc_fepll200_clk", > + "gcc_fepll500_clk", > }; > > static struct parent_map gcc_xo_200_map[] = { > @@ -59,7 +88,7 @@ static struct parent_map gcc_xo_200_map[] = { > > static const char * const gcc_xo_200[] = { > "xo", > - "fepll200", > + "gcc_fepll200_clk", > }; > > static struct parent_map gcc_xo_200_spi_map[] = { > @@ -69,7 +98,7 @@ static struct parent_map gcc_xo_200_spi_map[] = { > > static const char * const gcc_xo_200_spi[] = { > "xo", > - "fepll200", > + "gcc_fepll200_clk", > }; > > static struct parent_map gcc_xo_sdcc1_500_map[] = { > @@ -80,8 +109,8 @@ static struct parent_map gcc_xo_sdcc1_500_map[] = { > > static const char * const gcc_xo_sdcc1_500[] = { > "xo", > - "ddrpll", > - "fepll500", > + "gcc_apps_sdcc_clk", > + "gcc_fepll500_clk", > }; > > static struct parent_map gcc_xo_wcss2g_map[] = { > @@ -91,7 +120,7 @@ static struct parent_map gcc_xo_wcss2g_map[] = { > > static const char * const gcc_xo_wcss2g[] = { > "xo", > - "fepllwcss2g", > + "gcc_fepllwcss2g_clk", > }; > > static struct parent_map gcc_xo_wcss5g_map[] = { > @@ -101,7 +130,7 @@ static struct parent_map gcc_xo_wcss5g_map[] = { > > static const char * const gcc_xo_wcss5g[] = { > "xo", > - "fepllwcss5g", > + "gcc_fepllwcss5g_clk", > }; > > static struct parent_map gcc_xo_125_dly_map[] = { > @@ -111,7 +140,7 @@ static struct parent_map gcc_xo_125_dly_map[] = { > > static const char * const gcc_xo_125_dly[] = { > "xo", > - "fepll125dly", > + "gcc_fepll125dly_clk", > }; > > static struct parent_map gcc_xo_ddr_500_200_map[] = { > @@ -123,8 +152,8 @@ static struct parent_map gcc_xo_ddr_500_200_map[] = { > > static const char * const gcc_xo_ddr_500_200[] = { > "xo", > - "fepll200", > - "fepll500", > + "gcc_fepll200_clk", > + "gcc_fepll500_clk", > "ddrpllapss", > }; Was it necessary to change all these names? The gcc_ prefix doesn't seem to be adding much besides noise to this patch. > > @@ -506,7 +535,7 @@ static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = { > F(25000000, P_FEPLL500, 1, 1, 20), > F(50000000, P_FEPLL500, 1, 1, 10), > F(100000000, P_FEPLL500, 1, 1, 5), > - F(193000000, P_DDRPLL, 1, 0, 0), > + F(190000000, P_DDRPLL, 1, 0, 0), This looks like an unrelated bug fix. > { } > }; > > @@ -658,7 +687,7 @@ static struct clk_branch gcc_crypto_axi_clk = { > .hw.init = &(struct clk_init_data){ > .name = "gcc_crypto_axi_clk", > .parent_names = (const char *[]){ > - "fepll125", > + "gcc_fepll125_clk", > }, > .num_parents = 1, > .ops = &clk_branch2_ops, > @@ -675,7 +704,7 @@ static struct clk_branch gcc_crypto_clk = { > .hw.init = &(struct clk_init_data){ > .name = "gcc_crypto_clk", > .parent_names = (const char *[]){ > - "fepll125", > + "gcc_fepll125_clk", > }, > .num_parents = 1, > .ops = &clk_branch2_ops, > @@ -709,7 +738,7 @@ static struct clk_branch gcc_imem_axi_clk = { > .hw.init = &(struct clk_init_data){ > .name = "gcc_imem_axi_clk", > .parent_names = (const char *[]){ > - "fepll200", > + "gcc_fepll200_clk", > }, > .num_parents = 1, > .ops = &clk_branch2_ops, > @@ -773,7 +802,7 @@ static struct clk_branch gcc_pcie_axi_s_clk = { > .hw.init = &(struct clk_init_data){ > .name = "gcc_pcie_axi_s_clk", > .parent_names = (const char *[]){ > - "fepll200", > + "gcc_fepll200_clk", > }, > .num_parents = 1, > .ops = &clk_branch2_ops, > @@ -955,7 +984,7 @@ static struct clk_branch gcc_usb3_master_clk = { > .hw.init = &(struct clk_init_data){ > .name = "gcc_usb3_master_clk", > .parent_names = (const char *[]){ > - "fepll125", > + "gcc_fepll125_clk", > }, > .num_parents = 1, > .ops = &clk_branch2_ops, > @@ -1155,6 +1184,238 @@ static struct clk_branch gcc_wcss5g_rtc_clk = { > }, > }; > > +/* > + * Calculates the rate from parent rate and divider and round the rate > + * in Mhz. This function takes the parent rate in Khz and returns the > + * rate in Hz. > + */ > +static unsigned long clk_calc_divider_rate(unsigned long parent_rate, > + unsigned int div) > +{ > + u64 rate = parent_rate; > + > + do_div(rate, div); > + > + /* > + * This rate is in KHz so divide with 1000 and multiply with 1000000 s/KHz/kHz/ > + * to get the rate in Hz. > + */ > + do_div(rate, 1000); > + rate *= 1000000; > + > + return (unsigned long)rate; Unnecessary cast, please remove. > +} > + > +/* > + * Calculates the VCO rate for PLL. > + * VCO rate value is greater than unsigned long limit. Since this is an > + * intermediate clock node for actual PLL dividers, so it returns the > + * rate in Khz. The child nodes will return the value in Hz after its > + * divide operation. > + */ > +static unsigned long clk_regmap_vco_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct clk_pll_vco *rcg = to_clk_pll_vco(hw); > + u32 fdbkdiv, refclkdiv, cdiv; > + u64 vco; > + > + regmap_read(rcg->cdiv.clkr.regmap, rcg->cdiv.reg, &cdiv); > + refclkdiv = (cdiv >> rcg->cdiv.shift) & (BIT(rcg->cdiv.width) - 1); > + fdbkdiv = (cdiv >> rcg->fdbkdiv_shift) & (BIT(rcg->fdbkdiv_width) - 1); > + > + vco = parent_rate; > + do_div(vco, refclkdiv); > + do_div(vco, 1000); > + vco *= 2; > + vco *= fdbkdiv; > + > + return (unsigned long)vco; unnecessary cast. > +} > + > +const struct clk_ops clk_regmap_vco_ops = { static? > + .recalc_rate = clk_regmap_vco_recalc_rate, > +}; > + > +static struct clk_pll_vco gcc_apps_ddrpll_vco = { > + .fdbkdiv_shift = 16, > + .fdbkdiv_width = 8, > + .cdiv.reg = 0x2E020, lowercase hex please. > + .cdiv.shift = 24, > + .cdiv.width = 5, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_apps_ddrpll_vco", > + .parent_names = (const char *[]){ > + "xo", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_vco_ops, > + }, > + }, > +}; > + > +static struct clk_pll_vco gcc_fepll_vco = { > + .fdbkdiv_shift = 16, > + .fdbkdiv_width = 8, > + .cdiv.reg = 0x2F020, > + .cdiv.shift = 24, > + .cdiv.width = 5, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_fepll_vco", > + .parent_names = (const char *[]){ > + "xo", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_vco_ops, > + }, > + }, > +}; > + > +/* Calculates the rate for PLL divider. Style nit, /* goes on its own line > + * If the divider value is not fixed then it gets the actual divider value > + * from divider table. Then, it calculate the clock rate by dividing the > + * parent rate with actual divider value. > + */ > +static unsigned long clk_regmap_clk_div_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct clk_pll_div *rcg = to_clk_pll_div(hw); > + u32 cdiv, pre_div = 1; > + const struct clk_div_table *clkt; > + > + if (rcg->fixed_div) { > + pre_div = rcg->fixed_div; > + } else { > + regmap_read(rcg->cdiv.clkr.regmap, rcg->cdiv.reg, &cdiv); > + cdiv = (cdiv >> rcg->cdiv.shift) & (BIT(rcg->cdiv.width) - 1); > + > + for (clkt = rcg->div_table; clkt->div; clkt++) { > + if (clkt->val == cdiv) > + pre_div = clkt->div; > + } > + } > + > + return clk_calc_divider_rate(parent_rate, pre_div); > +}; > + > +const struct clk_ops clk_regmap_clk_div_ops = { static? > + .recalc_rate = clk_regmap_clk_div_recalc_rate, > +}; > + > +static struct clk_pll_div gcc_apps_sdcc_clk = { > + .fixed_div = 28, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_apps_sdcc_clk", > + .parent_names = (const char *[]){ > + "gcc_apps_ddrpll_vco", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_clk_div_ops, > + }, > + }, > +}; > + > +static struct clk_pll_div gcc_fepll125_clk = { > + .fixed_div = 32, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_fepll125_clk", > + .parent_names = (const char *[]){ > + "gcc_fepll_vco", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_clk_div_ops, > + }, > + }, > +}; > + > +static struct clk_pll_div gcc_fepll125dly_clk = { > + .fixed_div = 32, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_fepll125dly_clk", > + .parent_names = (const char *[]){ > + "gcc_fepll_vco", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_clk_div_ops, > + }, > + }, > +}; > + > +static struct clk_pll_div gcc_fepll200_clk = { > + .fixed_div = 20, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_fepll200_clk", > + .parent_names = (const char *[]){ > + "gcc_fepll_vco", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_clk_div_ops, > + }, > + }, > +}; > + > +static struct clk_pll_div gcc_fepll500_clk = { > + .fixed_div = 8, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_fepll500_clk", > + .parent_names = (const char *[]){ > + "gcc_fepll_vco", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_clk_div_ops, > + }, > + }, > +}; > + > +static const struct clk_div_table fepllwcss_clk_div_table[] = { > + {0, 15}, > + {1, 16}, > + {2, 18}, > + {3, 20}, Nitpick: Please add some spaces here { 0, 15 }, > + {}, > +}; > + > +static struct clk_pll_div gcc_fepllwcss2g_clk = { > + .cdiv.reg = 0x2F020, > + .cdiv.shift = 8, > + .cdiv.width = 2, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_fepllwcss2g_clk", > + .parent_names = (const char *[]){ > + "gcc_fepll_vco", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_clk_div_ops, > + }, > + }, > + .div_table = fepllwcss_clk_div_table > +}; > + > +static struct clk_pll_div gcc_fepllwcss5g_clk = { > + .cdiv.reg = 0x2F020, > + .cdiv.shift = 12, > + .cdiv.width = 2, > + .cdiv.clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gcc_fepllwcss5g_clk", > + .parent_names = (const char *[]){ > + "gcc_fepll_vco", > + }, > + .num_parents = 1, > + .ops = &clk_regmap_clk_div_ops, > + }, > + }, > + .div_table = fepllwcss_clk_div_table > +}; > + > static struct clk_regmap *gcc_ipq4019_clocks[] = { > [AUDIO_CLK_SRC] = &audio_clk_src.clkr, > [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, > @@ -1215,6 +1476,15 @@ static struct clk_regmap *gcc_ipq4019_clocks[] = { > [GCC_WCSS5G_CLK] = &gcc_wcss5g_clk.clkr, > [GCC_WCSS5G_REF_CLK] = &gcc_wcss5g_ref_clk.clkr, > [GCC_WCSS5G_RTC_CLK] = &gcc_wcss5g_rtc_clk.clkr, > + [GCC_APPS_DDRPLL_VCO] = &gcc_apps_ddrpll_vco.cdiv.clkr, > + [GCC_FEPLL_VCO] = &gcc_fepll_vco.cdiv.clkr, > + [GCC_SDCC_PLLDIV_CLK] = &gcc_apps_sdcc_clk.cdiv.clkr, > + [GCC_FEPLL125_CLK] = &gcc_fepll125_clk.cdiv.clkr, > + [GCC_FEPLL125DLY_CLK] = &gcc_fepll125dly_clk.cdiv.clkr, > + [GCC_FEPLL200_CLK] = &gcc_fepll200_clk.cdiv.clkr, > + [GCC_FEPLL500_CLK] = &gcc_fepll500_clk.cdiv.clkr, > + [GCC_FEPLL_WCSS2G_CLK] = &gcc_fepllwcss2g_clk.cdiv.clkr, > + [GCC_FEPLL_WCSS5G_CLK] = &gcc_fepllwcss5g_clk.cdiv.clkr, > }; > > static const struct qcom_reset_map gcc_ipq4019_resets[] = { > @@ -1295,7 +1565,7 @@ static const struct regmap_config gcc_ipq4019_regmap_config = { > .reg_bits = 32, > .reg_stride = 4, > .val_bits = 32, > - .max_register = 0x2dfff, > + .max_register = 0x2FFFF, Lowercase. > .fast_io = true, > }; -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe linux-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html