Message ID | 1615467092-6982-1-git-send-email-tdas@codeaurora.org (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | [v2] clk: qcom: clk-rcg2: Add support for duty-cycle for RCG | expand |
Quoting Taniya Das (2021-03-11 04:51:32) > The root clock generators with MND divider has the capability to support > change in duty-cycle by updating the 'D'. Add the clock ops which would > check all the boundary conditions and enable setting the desired duty-cycle > as per the consumer. > > Signed-off-by: Taniya Das <tdas@codeaurora.org> > --- > drivers/clk/qcom/clk-rcg2.c | 42 ++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 42 insertions(+) > > diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c > index 42f13a2..aac6893 100644 > --- a/drivers/clk/qcom/clk-rcg2.c > +++ b/drivers/clk/qcom/clk-rcg2.c > @@ -357,6 +357,46 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw, > return __clk_rcg2_set_rate(hw, rate, FLOOR); > } > > +static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) > +{ > + struct clk_rcg2 *rcg = to_clk_rcg2(hw); > + u32 notn_m_val, n_val, m_val, d_val, not2d_val, mask, duty_per; > + int ret; > + > + if (!rcg->mnd_width) > + return 0; Shouldn't we fail this call if the duty cycle can't be changed? Or have another set of clk ops that doesn't support this clk op if the mnd isn't present. > + > + mask = BIT(rcg->mnd_width) - 1; > + > + regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), ¬n_m_val); > + regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m_val); > + > + n_val = (~(notn_m_val) + m_val) & mask; > + > + duty_per = (duty->num * 100) / duty->den; > + > + /* Calculate 2d value */ > + d_val = DIV_ROUND_CLOSEST(n_val * duty_per * 2, 100); > + > + /* Check BIT WIDTHS OF 2d. If D is too big reduce Duty cycle. */ Why is BIT WIDTHS capitalized? And Duty? > + if (d_val > mask) > + d_val = mask; > + > + if ((d_val / 2) > (n_val - m_val)) > + d_val = (n_val - m_val) * 2; > + else if ((d_val / 2) < (m_val / 2)) > + d_val = m_val; > + > + not2d_val = ~d_val & mask; > + > + ret = regmap_update_bits(rcg->clkr.regmap, RCG_D_OFFSET(rcg), mask, > + not2d_val); > + if (ret) > + return ret; > + > + return update_config(rcg); > +} > + > const struct clk_ops clk_rcg2_ops = { > .is_enabled = clk_rcg2_is_enabled, > .get_parent = clk_rcg2_get_parent, > @@ -365,6 +405,7 @@ const struct clk_ops clk_rcg2_ops = { > .determine_rate = clk_rcg2_determine_rate, > .set_rate = clk_rcg2_set_rate, > .set_rate_and_parent = clk_rcg2_set_rate_and_parent, > + .set_duty_cycle = clk_rcg2_set_duty_cycle, Can you also implement get_duty_cycle? > }; > EXPORT_SYMBOL_GPL(clk_rcg2_ops); >
Hello Stephen, Thanks for your review. On 3/14/2021 4:29 AM, Stephen Boyd wrote: > Quoting Taniya Das (2021-03-11 04:51:32) >> The root clock generators with MND divider has the capability to support >> change in duty-cycle by updating the 'D'. Add the clock ops which would >> check all the boundary conditions and enable setting the desired duty-cycle >> as per the consumer. >> >> Signed-off-by: Taniya Das <tdas@codeaurora.org> >> --- >> drivers/clk/qcom/clk-rcg2.c | 42 ++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 42 insertions(+) >> >> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c >> index 42f13a2..aac6893 100644 >> --- a/drivers/clk/qcom/clk-rcg2.c >> +++ b/drivers/clk/qcom/clk-rcg2.c >> @@ -357,6 +357,46 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw, >> return __clk_rcg2_set_rate(hw, rate, FLOOR); >> } >> >> +static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) >> +{ >> + struct clk_rcg2 *rcg = to_clk_rcg2(hw); >> + u32 notn_m_val, n_val, m_val, d_val, not2d_val, mask, duty_per; >> + int ret; >> + >> + if (!rcg->mnd_width) >> + return 0; > > Shouldn't we fail this call if the duty cycle can't be changed? Or have > another set of clk ops that doesn't support this clk op if the mnd > isn't present. > Sure, will fail the call for non-MND(HID)RCGs, will be part of my next patch. >> + >> + mask = BIT(rcg->mnd_width) - 1; >> + >> + regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), ¬n_m_val); >> + regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m_val); >> + >> + n_val = (~(notn_m_val) + m_val) & mask; >> + >> + duty_per = (duty->num * 100) / duty->den; >> + >> + /* Calculate 2d value */ >> + d_val = DIV_ROUND_CLOSEST(n_val * duty_per * 2, 100); >> + >> + /* Check BIT WIDTHS OF 2d. If D is too big reduce Duty cycle. */ > > Why is BIT WIDTHS capitalized? And Duty? > Will take care of it in the next patch. >> + if (d_val > mask) >> + d_val = mask; >> + >> + if ((d_val / 2) > (n_val - m_val)) >> + d_val = (n_val - m_val) * 2; >> + else if ((d_val / 2) < (m_val / 2)) >> + d_val = m_val; >> + >> + not2d_val = ~d_val & mask; >> + >> + ret = regmap_update_bits(rcg->clkr.regmap, RCG_D_OFFSET(rcg), mask, >> + not2d_val); >> + if (ret) >> + return ret; >> + >> + return update_config(rcg); >> +} >> + >> const struct clk_ops clk_rcg2_ops = { >> .is_enabled = clk_rcg2_is_enabled, >> .get_parent = clk_rcg2_get_parent, >> @@ -365,6 +405,7 @@ const struct clk_ops clk_rcg2_ops = { >> .determine_rate = clk_rcg2_determine_rate, >> .set_rate = clk_rcg2_set_rate, >> .set_rate_and_parent = clk_rcg2_set_rate_and_parent, >> + .set_duty_cycle = clk_rcg2_set_duty_cycle, > > Can you also implement get_duty_cycle? > Sure, will implement the same. >> }; >> EXPORT_SYMBOL_GPL(clk_rcg2_ops); >>
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 42f13a2..aac6893 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -357,6 +357,46 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw, return __clk_rcg2_set_rate(hw, rate, FLOOR); } +static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + u32 notn_m_val, n_val, m_val, d_val, not2d_val, mask, duty_per; + int ret; + + if (!rcg->mnd_width) + return 0; + + mask = BIT(rcg->mnd_width) - 1; + + regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), ¬n_m_val); + regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m_val); + + n_val = (~(notn_m_val) + m_val) & mask; + + duty_per = (duty->num * 100) / duty->den; + + /* Calculate 2d value */ + d_val = DIV_ROUND_CLOSEST(n_val * duty_per * 2, 100); + + /* Check BIT WIDTHS OF 2d. If D is too big reduce Duty cycle. */ + if (d_val > mask) + d_val = mask; + + if ((d_val / 2) > (n_val - m_val)) + d_val = (n_val - m_val) * 2; + else if ((d_val / 2) < (m_val / 2)) + d_val = m_val; + + not2d_val = ~d_val & mask; + + ret = regmap_update_bits(rcg->clkr.regmap, RCG_D_OFFSET(rcg), mask, + not2d_val); + if (ret) + return ret; + + return update_config(rcg); +} + const struct clk_ops clk_rcg2_ops = { .is_enabled = clk_rcg2_is_enabled, .get_parent = clk_rcg2_get_parent, @@ -365,6 +405,7 @@ const struct clk_ops clk_rcg2_ops = { .determine_rate = clk_rcg2_determine_rate, .set_rate = clk_rcg2_set_rate, .set_rate_and_parent = clk_rcg2_set_rate_and_parent, + .set_duty_cycle = clk_rcg2_set_duty_cycle, }; EXPORT_SYMBOL_GPL(clk_rcg2_ops); @@ -376,6 +417,7 @@ const struct clk_ops clk_rcg2_floor_ops = { .determine_rate = clk_rcg2_determine_floor_rate, .set_rate = clk_rcg2_set_floor_rate, .set_rate_and_parent = clk_rcg2_set_floor_rate_and_parent, + .set_duty_cycle = clk_rcg2_set_duty_cycle, }; EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
The root clock generators with MND divider has the capability to support change in duty-cycle by updating the 'D'. Add the clock ops which would check all the boundary conditions and enable setting the desired duty-cycle as per the consumer. Signed-off-by: Taniya Das <tdas@codeaurora.org> --- drivers/clk/qcom/clk-rcg2.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.