clk: sunxi-ng: nm: Add support for sigma-delta modulation
Some of the N-M-style clocks, namely the PLLs, support sigma-delta modulation to do fractional-N frequency synthesis. This is used in the audio PLL to generate the exact frequency the audio blocks need. These frequencies can not be generated with integer N-M factors. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
This commit is contained in:
parent
05d2eaac96
commit
392ba5fafc
|
@ -90,6 +90,14 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
|
|||
if (!m)
|
||||
m++;
|
||||
|
||||
if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) {
|
||||
unsigned long rate =
|
||||
ccu_sdm_helper_read_rate(&nm->common, &nm->sdm,
|
||||
m, n);
|
||||
if (rate)
|
||||
return rate;
|
||||
}
|
||||
|
||||
return parent_rate * n / m;
|
||||
}
|
||||
|
||||
|
@ -102,6 +110,9 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate))
|
||||
return rate;
|
||||
|
||||
if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate))
|
||||
return rate;
|
||||
|
||||
_nm.min_n = nm->n.min ?: 1;
|
||||
_nm.max_n = nm->n.max ?: 1 << nm->n.width;
|
||||
_nm.min_m = 1;
|
||||
|
@ -143,7 +154,16 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
_nm.min_m = 1;
|
||||
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
|
||||
|
||||
ccu_nm_find_best(parent_rate, rate, &_nm);
|
||||
if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) {
|
||||
ccu_sdm_helper_enable(&nm->common, &nm->sdm, rate);
|
||||
|
||||
/* Sigma delta modulation requires specific N and M factors */
|
||||
ccu_sdm_helper_get_factors(&nm->common, &nm->sdm, rate,
|
||||
&_nm.m, &_nm.n);
|
||||
} else {
|
||||
ccu_sdm_helper_disable(&nm->common, &nm->sdm);
|
||||
ccu_nm_find_best(parent_rate, rate, &_nm);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(nm->common.lock, flags);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ccu_div.h"
|
||||
#include "ccu_frac.h"
|
||||
#include "ccu_mult.h"
|
||||
#include "ccu_sdm.h"
|
||||
|
||||
/*
|
||||
* struct ccu_nm - Definition of an N-M clock
|
||||
|
@ -33,10 +34,34 @@ struct ccu_nm {
|
|||
struct ccu_mult_internal n;
|
||||
struct ccu_div_internal m;
|
||||
struct ccu_frac_internal frac;
|
||||
struct ccu_sdm_internal sdm;
|
||||
|
||||
struct ccu_common common;
|
||||
};
|
||||
|
||||
#define SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(_struct, _name, _parent, _reg, \
|
||||
_nshift, _nwidth, \
|
||||
_mshift, _mwidth, \
|
||||
_sdm_table, _sdm_en, \
|
||||
_sdm_reg, _sdm_reg_en, \
|
||||
_gate, _lock, _flags) \
|
||||
struct ccu_nm _struct = { \
|
||||
.enable = _gate, \
|
||||
.lock = _lock, \
|
||||
.n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
|
||||
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
|
||||
.sdm = _SUNXI_CCU_SDM(_sdm_table, _sdm_en, \
|
||||
_sdm_reg, _sdm_reg_en),\
|
||||
.common = { \
|
||||
.reg = _reg, \
|
||||
.features = CCU_FEATURE_SIGMA_DELTA_MOD, \
|
||||
.hw.init = CLK_HW_INIT(_name, \
|
||||
_parent, \
|
||||
&ccu_nm_ops, \
|
||||
_flags), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(_struct, _name, _parent, _reg, \
|
||||
_nshift, _nwidth, \
|
||||
_mshift, _mwidth, \
|
||||
|
|
Loading…
Reference in New Issue