summaryrefslogtreecommitdiff
path: root/drivers/phy/freescale
diff options
context:
space:
mode:
authorAdam Ford <aford173@gmail.com>2024-09-14 06:27:48 -0500
committerVinod Koul <vkoul@kernel.org>2024-10-17 18:43:36 +0530
commit058ea4a06704c6ad3032bdb3ead9ed3dc1f7fe6e (patch)
treedd2d0b5a3b39f8bebf888d4902a262104789fa08 /drivers/phy/freescale
parent1951dbb41d1dff7c135eed4fa1a6330df6971549 (diff)
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 <aford173@gmail.com> Reviewed-by: Dominique Martinet <dominique.martinet@atmark-techno.com> Tested-by: Dominique Martinet <dominique.martinet@atmark-techno.com> Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de> Link: https://lore.kernel.org/r/20240914112816.520224-5-aford173@gmail.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers/phy/freescale')
-rw-r--r--drivers/phy/freescale/phy-fsl-samsung-hdmi.c40
1 files changed, 29 insertions, 11 deletions
diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
index 029de69fbeaf..381742e8b618 100644
--- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
+++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
@@ -577,6 +577,16 @@ static void fsl_samsung_hdmi_calculate_phy(struct phy_config *cal_phy, unsigned
/* pll_div_regs 3-6 are fixed and pre-defined already */
}
+static u32 fsl_samsung_hdmi_phy_get_closest_rate(unsigned long rate,
+ u32 int_div_clk, u32 frac_div_clk)
+{
+ /* Calculate the absolute value of the differences and return whichever is closest */
+ if (abs((long)rate - (long)int_div_clk) < abs((long)(rate - (long)frac_div_clk)))
+ return int_div_clk;
+
+ return frac_div_clk;
+}
+
static long phy_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate)
{
@@ -615,6 +625,15 @@ static int phy_use_fract_div(struct fsl_samsung_hdmi_phy *phy, const struct phy_
return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
}
+static int phy_use_integer_div(struct fsl_samsung_hdmi_phy *phy,
+ const struct phy_config *int_div_clk)
+{
+ phy->cur_cfg = &calculated_phy_pll_cfg;
+ dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n",
+ phy->cur_cfg->pixclk);
+ return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
+}
+
static int phy_clk_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
@@ -636,20 +655,19 @@ static int phy_clk_set_rate(struct clk_hw *hw,
* and use it if that value is an exact match.
*/
int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s);
- if (int_div_clk == rate) {
- dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n",
- int_div_clk);
-
- fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s);
- phy->cur_cfg = &calculated_phy_pll_cfg;
- return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
- }
+ fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s);
+ if (int_div_clk == rate)
+ return phy_use_integer_div(phy, &calculated_phy_pll_cfg);
/*
- * If neither the fractional divider nor the integer divider can find an exact value
- * fall back to using the fractional divider
+ * Compare the difference between the integer clock and the fractional clock against
+ * the desired clock and which whichever is closest.
*/
- return phy_use_fract_div(phy, fract_div_phy);
+ if (fsl_samsung_hdmi_phy_get_closest_rate(rate, int_div_clk,
+ fract_div_phy->pixclk) == fract_div_phy->pixclk)
+ return phy_use_fract_div(phy, fract_div_phy);
+ else
+ return phy_use_integer_div(phy, &calculated_phy_pll_cfg);
}
static const struct clk_ops phy_clk_ops = {