• Katsuhiro Suzuki's avatar
    clk: fractional-divider: check parent rate only if flag is set · 2c8340ca
    Katsuhiro Suzuki authored
    [ Upstream commit d13501a2 ]
    
    Custom approximation of fractional-divider may not need parent clock
    rate checking. For example Rockchip SoCs work fine using grand parent
    clock rate even if target rate is greater than parent.
    
    This patch checks parent clock rate only if CLK_SET_RATE_PARENT flag
    is set.
    
    For detailed example, clock tree of Rockchip I2S audio hardware.
      - Clock rate of CPLL is 1.2GHz, GPLL is 491.52MHz.
      - i2s1_div is integer divider can divide N (N is 1~128).
        Input clock is CPLL or GPLL. Initial divider value is N = 1.
        Ex) PLL = CPLL, N = 10, i2s1_div output rate is
          CPLL / 10 = 1.2GHz / 10 = 120MHz
      - i2s1_frac is fractional divider can divide input to x/y, x and
        y are 16bit integer.
    
    CPLL --> | selector | ---> i2s1_div -+--> | selector | --> I2S1 MCLK
    GPLL --> |          | ,--------------'    |          |
                          `--> i2s1_frac ---> |          |
    
    Clock mux system try to choose suitable one from i2s1_div and
    i2s1_frac for master clock (MCLK) of I2S1.
    
    Bad scenario as follows:
      - Try to set MCLK to 8.192MHz (32kHz audio replay)
        Candidate setting is
        - i2s1_div: GPLL / 60 = 8.192MHz
        i2s1_div candidate is exactly same as target clock rate, so mux
        choose this clock source. i2s1_div output rate is changed
        491.52MHz -> 8.192MHz
    
      - After that try to set to 11.2896MHz (44.1kHz audio replay)
        Candidate settings are
        - i2s1_div : CPLL / 107 = 11.214945MHz
        - i2s1_frac: i2s1_div   = 8.192MHz
          This is because clk_fd_round_rate() thinks target rate
          (11.2896MHz) is higher than parent rate (i2s1_div = 8.192MHz)
          and returns parent clock rate.
    
    Above is current upstreamed behavior. Clock mux system choose
    i2s1_div, but this clock rate is not acceptable for I2S driver, so
    users cannot replay audio.
    
    Expected behavior is:
      - Try to set master clock to 11.2896MHz (44.1kHz audio replay)
        Candidate settings are
        - i2s1_div : CPLL / 107          = 11.214945MHz
        - i2s1_frac: i2s1_div * 147/6400 = 11.2896MHz
                     Change i2s1_div to GPLL / 1 = 491.52MHz at same
                     time.
    
    If apply this commit, clk_fd_round_rate() calls custom approximate
    function of Rockchip even if target rate is higher than parent.
    Custom function changes both grand parent (i2s1_div) and parent
    (i2s_frac) settings at same time. Clock mux system can choose
    i2s1_frac and audio works fine.
    Signed-off-by: default avatarKatsuhiro Suzuki <katsuhiro@katsuster.net>
    Reviewed-by: default avatarHeiko Stuebner <heiko@sntech.de>
    [sboyd@kernel.org: Make function into a macro instead]
    Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
    Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
    2c8340ca
clk-fractional-divider.c 4.71 KB