diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic32x4-clk.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic32x4-clk.c | 54 |
1 files changed, 35 insertions, 19 deletions
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index 156c153c12ab..5c0a76a4a106 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -204,18 +204,19 @@ static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw, return clk_aic32x4_pll_calc_rate(&settings, parent_rate); } -static long clk_aic32x4_pll_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) +static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_aic32x4_pll_muldiv settings; int ret; - ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate); + ret = clk_aic32x4_pll_calc_muldiv(&settings, req->rate, req->best_parent_rate); if (ret < 0) - return 0; + return -EINVAL; + + req->rate = clk_aic32x4_pll_calc_rate(&settings, req->best_parent_rate); - return clk_aic32x4_pll_calc_rate(&settings, *parent_rate); + return 0; } static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, @@ -230,7 +231,14 @@ static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, if (ret < 0) return -EINVAL; - return clk_aic32x4_pll_set_muldiv(pll, &settings); + ret = clk_aic32x4_pll_set_muldiv(pll, &settings); + if (ret) + return ret; + + /* 10ms is the delay to wait before the clocks are stable */ + msleep(10); + + return 0; } static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index) @@ -259,7 +267,7 @@ static const struct clk_ops aic32x4_pll_ops = { .unprepare = clk_aic32x4_pll_unprepare, .is_prepared = clk_aic32x4_pll_is_prepared, .recalc_rate = clk_aic32x4_pll_recalc_rate, - .round_rate = clk_aic32x4_pll_round_rate, + .determine_rate = clk_aic32x4_pll_determine_rate, .set_rate = clk_aic32x4_pll_set_rate, .set_parent = clk_aic32x4_pll_set_parent, .get_parent = clk_aic32x4_pll_get_parent, @@ -285,6 +293,7 @@ static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw) } static const struct clk_ops aic32x4_codec_clkin_ops = { + .determine_rate = clk_hw_determine_rate_no_reparent, .set_parent = clk_aic32x4_codec_clkin_set_parent, .get_parent = clk_aic32x4_codec_clkin_get_parent, }; @@ -312,42 +321,49 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, u8 divisor; divisor = DIV_ROUND_UP(parent_rate, rate); - if (divisor > 128) + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; return regmap_update_bits(div->regmap, div->reg, AIC32X4_DIV_MASK, divisor); } -static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long divisor; - divisor = DIV_ROUND_UP(*parent_rate, rate); - if (divisor > 128) + divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate); + if (divisor > AIC32X4_DIV_MAX) return -EINVAL; - return DIV_ROUND_UP(*parent_rate, divisor); + req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor); + return 0; } static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); - unsigned int val; + int err; + + err = regmap_read(div->regmap, div->reg, &val); + if (err) + return 0; - regmap_read(div->regmap, div->reg, &val); + val &= AIC32X4_DIV_MASK; + if (!val) + val = AIC32X4_DIV_MAX; - return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK); + return DIV_ROUND_UP(parent_rate, val); } static const struct clk_ops aic32x4_div_ops = { .prepare = clk_aic32x4_div_prepare, .unprepare = clk_aic32x4_div_unprepare, .set_rate = clk_aic32x4_div_set_rate, - .round_rate = clk_aic32x4_div_round_rate, + .determine_rate = clk_aic32x4_div_determine_rate, .recalc_rate = clk_aic32x4_div_recalc_rate, }; @@ -375,7 +391,7 @@ static const struct clk_ops aic32x4_bdiv_ops = { .set_parent = clk_aic32x4_bdiv_set_parent, .get_parent = clk_aic32x4_bdiv_get_parent, .set_rate = clk_aic32x4_div_set_rate, - .round_rate = clk_aic32x4_div_round_rate, + .determine_rate = clk_aic32x4_div_determine_rate, .recalc_rate = clk_aic32x4_div_recalc_rate, }; |