Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Adam Ford and committed by
Vinod Koul
058ea4a0 1951dbb4

+29 -11
+29 -11
drivers/phy/freescale/phy-fsl-samsung-hdmi.c
··· 577 577 /* pll_div_regs 3-6 are fixed and pre-defined already */ 578 578 } 579 579 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 + 580 590 static long phy_clk_round_rate(struct clk_hw *hw, 581 591 unsigned long rate, unsigned long *parent_rate) 582 592 { ··· 625 615 return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); 626 616 } 627 617 618 + static int phy_use_integer_div(struct fsl_samsung_hdmi_phy *phy, 619 + const struct phy_config *int_div_clk) 620 + { 621 + phy->cur_cfg = &calculated_phy_pll_cfg; 622 + dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n", 623 + phy->cur_cfg->pixclk); 624 + return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); 625 + } 626 + 628 627 static int phy_clk_set_rate(struct clk_hw *hw, 629 628 unsigned long rate, unsigned long parent_rate) 630 629 { ··· 655 636 * and use it if that value is an exact match. 656 637 */ 657 638 int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s); 658 - if (int_div_clk == rate) { 659 - dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n", 660 - int_div_clk); 661 - 662 - fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s); 663 - phy->cur_cfg = &calculated_phy_pll_cfg; 664 - return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); 665 - } 639 + fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s); 640 + if (int_div_clk == rate) 641 + return phy_use_integer_div(phy, &calculated_phy_pll_cfg); 666 642 667 643 /* 668 - * If neither the fractional divider nor the integer divider can find an exact value 669 - * fall back to using the fractional divider 644 + * Compare the difference between the integer clock and the fractional clock against 645 + * the desired clock and which whichever is closest. 670 646 */ 671 - return phy_use_fract_div(phy, fract_div_phy); 647 + if (fsl_samsung_hdmi_phy_get_closest_rate(rate, int_div_clk, 648 + fract_div_phy->pixclk) == fract_div_phy->pixclk) 649 + return phy_use_fract_div(phy, fract_div_phy); 650 + else 651 + return phy_use_integer_div(phy, &calculated_phy_pll_cfg); 672 652 } 673 653 674 654 static const struct clk_ops phy_clk_ops = {