Skip to content

Commit 058ea4a

Browse files
aford173vinodkoul
authored andcommitted
phy: freescale: fsl-samsung-hdmi: Use closest divider
Currently, if the clock values cannot be set to the exact rate, the round_rate and set_rate functions use the closest value found in the look-up-table. In preparation of removing values from the LUT that can be calculated evenly with the integer calculator, it's necessary to ensure to check both the look-up-table and the integer divider clock values to get the closest values to the requested value. It does this by measuring the difference between the requested clock value and the closest value in both integer divider calucator and the fractional clock look-up-table. Which ever has the smallest difference between them is returned as the closest rate. Signed-off-by: Adam Ford <[email protected]> Reviewed-by: Dominique Martinet <[email protected]> Tested-by: Dominique Martinet <[email protected]> Reviewed-by: Frieder Schrempf <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 1951dbb commit 058ea4a

File tree

1 file changed

+29
-11
lines changed

1 file changed

+29
-11
lines changed

drivers/phy/freescale/phy-fsl-samsung-hdmi.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,16 @@ static void fsl_samsung_hdmi_calculate_phy(struct phy_config *cal_phy, unsigned
577577
/* pll_div_regs 3-6 are fixed and pre-defined already */
578578
}
579579

580+
static u32 fsl_samsung_hdmi_phy_get_closest_rate(unsigned long rate,
581+
u32 int_div_clk, u32 frac_div_clk)
582+
{
583+
/* Calculate the absolute value of the differences and return whichever is closest */
584+
if (abs((long)rate - (long)int_div_clk) < abs((long)(rate - (long)frac_div_clk)))
585+
return int_div_clk;
586+
587+
return frac_div_clk;
588+
}
589+
580590
static long phy_clk_round_rate(struct clk_hw *hw,
581591
unsigned long rate, unsigned long *parent_rate)
582592
{
@@ -615,6 +625,15 @@ static int phy_use_fract_div(struct fsl_samsung_hdmi_phy *phy, const struct phy_
615625
return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
616626
}
617627

628+
static int phy_use_integer_div(struct fsl_samsung_hdmi_phy *phy,
629+
const struct phy_config *int_div_clk)
630+
{
631+
phy->cur_cfg = &calculated_phy_pll_cfg;
632+
dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n",
633+
phy->cur_cfg->pixclk);
634+
return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
635+
}
636+
618637
static int phy_clk_set_rate(struct clk_hw *hw,
619638
unsigned long rate, unsigned long parent_rate)
620639
{
@@ -636,20 +655,19 @@ static int phy_clk_set_rate(struct clk_hw *hw,
636655
* and use it if that value is an exact match.
637656
*/
638657
int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s);
639-
if (int_div_clk == rate) {
640-
dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n",
641-
int_div_clk);
642-
643-
fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s);
644-
phy->cur_cfg = &calculated_phy_pll_cfg;
645-
return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
646-
}
658+
fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s);
659+
if (int_div_clk == rate)
660+
return phy_use_integer_div(phy, &calculated_phy_pll_cfg);
647661

648662
/*
649-
* If neither the fractional divider nor the integer divider can find an exact value
650-
* fall back to using the fractional divider
663+
* Compare the difference between the integer clock and the fractional clock against
664+
* the desired clock and which whichever is closest.
651665
*/
652-
return phy_use_fract_div(phy, fract_div_phy);
666+
if (fsl_samsung_hdmi_phy_get_closest_rate(rate, int_div_clk,
667+
fract_div_phy->pixclk) == fract_div_phy->pixclk)
668+
return phy_use_fract_div(phy, fract_div_phy);
669+
else
670+
return phy_use_integer_div(phy, &calculated_phy_pll_cfg);
653671
}
654672

655673
static const struct clk_ops phy_clk_ops = {

0 commit comments

Comments
 (0)