Saturday, July 21, 2018

Linux Clock - clk_register_fractional_divider

note for myself (all the clock description is at clk-provider.h):

/**
 * struct clk_fractional_divider - adjustable fractional divider clock
 *
 * @hw:  handle between common and hardware-specific interfaces
 * @reg: register containing the divider
 * @mshift: shift to the numerator bit field
 * @mwidth: width of the numerator bit field
 * @nshift: shift to the denominator bit field
 * @nwidth: width of the denominator bit field
 * @lock: register lock
 *
 * Clock with adjustable fractional divider affecting its output frequency.
 */
struct clk_fractional_divider {
 struct clk_hw hw;
 void __iomem *reg;
 u8  mshift;
 u8  mwidth;
 u32  mmask;
 u8  nshift;
 u8  nwidth;
 u32  nmask;
 u8  flags;
 void  (*approximation)(struct clk_hw *hw,
    unsigned long rate, unsigned long *parent_rate,
    unsigned long *m, unsigned long *n);
 spinlock_t *lock;
};

#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)

extern const struct clk_ops clk_fractional_divider_ops;
struct clk *clk_register_fractional_divider(struct device *dev,
  const char *name, const char *parent_name, unsigned long flags,
  void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
  u8 clk_divider_flags, spinlock_t *lock);
struct clk_hw *clk_hw_register_fractional_divider(struct device *dev,
  const char *name, const char *parent_name, unsigned long flags,
  void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
  u8 clk_divider_flags, spinlock_t *lock);
void clk_hw_unregister_fractional_divider(struct clk_hw *hw);

No reference code is using this function "clk_register_fractional_divider" at the time of writing.

Go for code reading:
struct clk_hw *clk_hw_register_fractional_divider(struct device *dev,
  const char *name, const char *parent_name, unsigned long flags,
  void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
  u8 clk_divider_flags, spinlock_t *lock)
{
 struct clk_fractional_divider *fd;
 struct clk_init_data init;
 struct clk_hw *hw;
 int ret;

 fd = kzalloc(sizeof(*fd), GFP_KERNEL);
 if (!fd)
  return ERR_PTR(-ENOMEM);

 init.name = name;
 init.ops = &clk_fractional_divider_ops;
 init.flags = flags | CLK_IS_BASIC;
 init.parent_names = parent_name ? &parent_name : NULL;
 init.num_parents = parent_name ? 1 : 0;

 fd->reg = reg;
 fd->mshift = mshift;
 fd->mwidth = mwidth;
 fd->mmask = GENMASK(mwidth - 1, 0) << mshift;
 fd->nshift = nshift;
 fd->nwidth = nwidth;
 fd->nmask = GENMASK(nwidth - 1, 0) << nshift;
 fd->flags = clk_divider_flags;
 fd->lock = lock;
 fd->hw.init = &init;

 hw = &fd->hw;
 ret = clk_hw_register(dev, hw);
 if (ret) {
  kfree(fd);
  hw = ERR_PTR(ret);
 }

 return hw;
}
EXPORT_SYMBOL_GPL(clk_hw_register_fractional_divider);

Identified 3 items:
&clk_fractional_divider_ops - functions
mshift, mwidth - numerator
nshift, nwidth - denumerator

We need found out how the mshift, mwidth, nshift, nwidth are used through "clk_fractional_divider_ops".
const struct clk_ops clk_fractional_divider_ops = {
 .recalc_rate = clk_fd_recalc_rate,
 .round_rate = clk_fd_round_rate,
 .set_rate = clk_fd_set_rate,
};
EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);

Let take this "clk_fd_set_rate" for study

static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
      unsigned long parent_rate)
{
 struct clk_fractional_divider *fd = to_clk_fd(hw);
 unsigned long flags = 0;
 unsigned long m, n;
 u32 val;

 rational_best_approximation(rate, parent_rate,
   GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
   &m, &n);

 if (fd->lock)
  spin_lock_irqsave(fd->lock, flags);
 else
  __acquire(fd->lock);

 val = clk_readl(fd->reg);
 val &= ~(fd->mmask | fd->nmask);
 val |= (m << fd->mshift) | (n << fd->nshift);
 clk_writel(val, fd->reg);

 if (fd->lock)
  spin_unlock_irqrestore(fd->lock, flags);
 else
  __release(fd->lock);

 return 0;
}

The highlighted in green is the main function that help to calculate best numerator and denominator to get the best approximate rate.

/*
 * calculate best rational approximation for a given fraction
 * taking into account restricted register size, e.g. to find
 * appropriate values for a pll with 5 bit denominator and
 * 8 bit numerator register fields, trying to set up with a
 * frequency ratio of 3.1415, one would say:
 *
 * rational_best_approximation(31415, 10000,
 *  (1 << 8) - 1, (1 << 5) - 1, &n, &d);
 *
 * you may look at given_numerator as a fixed point number,
 * with the fractional part size described in given_denominator.
 *
 * for theoretical background, see:
 * http://en.wikipedia.org/wiki/Continued_fraction
 */

void rational_best_approximation(
 unsigned long given_numerator, unsigned long given_denominator,
 unsigned long max_numerator, unsigned long max_denominator,
 unsigned long *best_numerator, unsigned long *best_denominator)

while, below perform the task to set register to get correct value.
  val = clk_readl(fd->reg);
 val &= ~(fd->mmask | fd->nmask);
 val |= (m << fd->mshift) | (n << fd->nshift);
 clk_writel(val, fd->reg);

One thing that I am still in doubt, is where the clock rate is defined. Need to study more.

No comments:

Post a Comment