Skip to content

Commit

Permalink
clk: sunxi-ng: nm: Add support for sigma-delta modulation
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chen-Yu Tsai authored and Maxime Ripard committed Oct 13, 2017
1 parent 05d2eaa commit 392ba5f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 1 deletion.
22 changes: 21 additions & 1 deletion drivers/clk/sunxi-ng/ccu_nm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
25 changes: 25 additions & 0 deletions drivers/clk/sunxi-ng/ccu_nm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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, \
Expand Down

0 comments on commit 392ba5f

Please sign in to comment.