Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/clk/meson/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 4 kB image not shown  

Quelle  clk-mpll.c   Sprache: C

 
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * Copyright (c) 2016 AmLogic, Inc.
 * Author: Michael Turquette <mturquette@baylibre.com>
 */


/*
 * MultiPhase Locked Loops are outputs from a PLL with additional frequency
 * scaling capabilities. MPLL rates are calculated as:
 *
 * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
 */


#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/spinlock.h>

#include "clk-regmap.h"
#include "clk-mpll.h"

#define SDM_DEN 16384
#define N2_MIN 4
#define N2_MAX 511

static inline struct meson_clk_mpll_data *
meson_clk_mpll_data(struct clk_regmap *clk)
{
 return (struct meson_clk_mpll_data *)clk->data;
}

static long rate_from_params(unsigned long parent_rate,
        unsigned int sdm,
        unsigned int n2)
{
 unsigned long divisor = (SDM_DEN * n2) + sdm;

 if (n2 < N2_MIN)
  return -EINVAL;

 return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
}

static void params_from_rate(unsigned long requested_rate,
        unsigned long parent_rate,
        unsigned int *sdm,
        unsigned int *n2,
        u8 flags)
{
 uint64_t div = parent_rate;
 uint64_t frac = do_div(div, requested_rate);

 frac *= SDM_DEN;

 if (flags & CLK_MESON_MPLL_ROUND_CLOSEST)
  *sdm = DIV_ROUND_CLOSEST_ULL(frac, requested_rate);
 else
  *sdm = DIV_ROUND_UP_ULL(frac, requested_rate);

 if (*sdm == SDM_DEN) {
  *sdm = 0;
  div += 1;
 }

 if (div < N2_MIN) {
  *n2 = N2_MIN;
  *sdm = 0;
 } else if (div > N2_MAX) {
  *n2 = N2_MAX;
  *sdm = SDM_DEN - 1;
 } else {
  *n2 = div;
 }
}

static unsigned long mpll_recalc_rate(struct clk_hw *hw,
  unsigned long parent_rate)
{
 struct clk_regmap *clk = to_clk_regmap(hw);
 struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
 unsigned int sdm, n2;
 long rate;

 sdm = meson_parm_read(clk->map, &mpll->sdm);
 n2 = meson_parm_read(clk->map, &mpll->n2);

 rate = rate_from_params(parent_rate, sdm, n2);
 return rate < 0 ? 0 : rate;
}

static int mpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
 struct clk_regmap *clk = to_clk_regmap(hw);
 struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
 unsigned int sdm, n2;
 long rate;

 params_from_rate(req->rate, req->best_parent_rate, &sdm, &n2,
    mpll->flags);

 rate = rate_from_params(req->best_parent_rate, sdm, n2);
 if (rate < 0)
  return rate;

 req->rate = rate;
 return 0;
}

static int mpll_set_rate(struct clk_hw *hw,
    unsigned long rate,
    unsigned long parent_rate)
{
 struct clk_regmap *clk = to_clk_regmap(hw);
 struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
 unsigned int sdm, n2;

 params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags);

 /* Set the fractional part */
 meson_parm_write(clk->map, &mpll->sdm, sdm);

 /* Set the integer divider part */
 meson_parm_write(clk->map, &mpll->n2, n2);

 return 0;
}

static int mpll_init(struct clk_hw *hw)
{
 struct clk_regmap *clk = to_clk_regmap(hw);
 struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
 int ret;

 ret = clk_regmap_init(hw);
 if (ret)
  return ret;

 if (mpll->init_count)
  regmap_multi_reg_write(clk->map, mpll->init_regs,
           mpll->init_count);

 /* Enable the fractional part */
 meson_parm_write(clk->map, &mpll->sdm_en, 1);

 /* Set spread spectrum if possible */
 if (MESON_PARM_APPLICABLE(&mpll->ssen)) {
  unsigned int ss =
   mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0;
  meson_parm_write(clk->map, &mpll->ssen, ss);
 }

 /* Set the magic misc bit if required */
 if (MESON_PARM_APPLICABLE(&mpll->misc))
  meson_parm_write(clk->map, &mpll->misc, 1);

 return 0;
}

const struct clk_ops meson_clk_mpll_ro_ops = {
 .init  = clk_regmap_init,
 .recalc_rate = mpll_recalc_rate,
 .determine_rate = mpll_determine_rate,
};
EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ro_ops, "CLK_MESON");

const struct clk_ops meson_clk_mpll_ops = {
 .recalc_rate = mpll_recalc_rate,
 .determine_rate = mpll_determine_rate,
 .set_rate = mpll_set_rate,
 .init  = mpll_init,
};
EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ops, "CLK_MESON");

MODULE_DESCRIPTION("Amlogic MPLL driver");
MODULE_AUTHOR("Michael Turquette ");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("CLK_MESON");

Messung V0.5
C=95 H=88 G=91

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.