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

Quelle  clk-hfpll.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, The Linux Foundation. All rights reserved.

#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/spinlock.h>

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

#define PLL_OUTCTRL BIT(0)
#define PLL_BYPASSNL BIT(1)
#define PLL_RESET_N BIT(2)

/* Initialize a HFPLL at a given rate and enable it. */
static void __clk_hfpll_init_once(struct clk_hw *hw)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;

 if (likely(h->init_done))
  return;

 /* Configure PLL parameters for integer mode. */
 if (hd->config_val)
  regmap_write(regmap, hd->config_reg, hd->config_val);
 regmap_write(regmap, hd->m_reg, 0);
 regmap_write(regmap, hd->n_reg, 1);

 if (hd->user_reg) {
  u32 regval = hd->user_val;
  unsigned long rate;

  rate = clk_hw_get_rate(hw);

  /* Pick the right VCO. */
  if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
   regval |= hd->user_vco_mask;
  regmap_write(regmap, hd->user_reg, regval);
 }

 /* Write L_VAL from conf if it exist */
 if (hd->l_val)
  regmap_write(regmap, hd->l_reg, hd->l_val);

 if (hd->droop_reg)
  regmap_write(regmap, hd->droop_reg, hd->droop_val);

 h->init_done = true;
}

static void __clk_hfpll_enable(struct clk_hw *hw)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;
 u32 val;

 __clk_hfpll_init_once(hw);

 /* Disable PLL bypass mode. */
 regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);

 /*
 * H/W requires a 5us delay between disabling the bypass and
 * de-asserting the reset. Delay 10us just to be safe.
 */

 udelay(10);

 /* De-assert active-low PLL reset. */
 regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);

 /* Wait for PLL to lock. */
 if (hd->status_reg)
  /*
 * Busy wait. Should never timeout, we add a timeout to
 * prevent any sort of stall.
 */

  regmap_read_poll_timeout(regmap, hd->status_reg, val,
      !(val & BIT(hd->lock_bit)), 0,
      100 * USEC_PER_MSEC);
 else
  udelay(60);

 /* Enable PLL output. */
 regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
}

/* Enable an already-configured HFPLL. */
static int clk_hfpll_enable(struct clk_hw *hw)
{
 unsigned long flags;
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;
 u32 mode;

 spin_lock_irqsave(&h->lock, flags);
 regmap_read(regmap, hd->mode_reg, &mode);
 if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
  __clk_hfpll_enable(hw);
 spin_unlock_irqrestore(&h->lock, flags);

 return 0;
}

static void __clk_hfpll_disable(struct clk_hfpll *h)
{
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;

 /*
 * Disable the PLL output, disable test mode, enable the bypass mode,
 * and assert the reset.
 */

 regmap_update_bits(regmap, hd->mode_reg,
      PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
}

static void clk_hfpll_disable(struct clk_hw *hw)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 unsigned long flags;

 spin_lock_irqsave(&h->lock, flags);
 __clk_hfpll_disable(h);
 spin_unlock_irqrestore(&h->lock, flags);
}

static int clk_hfpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 unsigned long rrate;

 req->rate = clamp(req->rate, hd->min_rate, hd->max_rate);

 rrate = DIV_ROUND_UP(req->rate, req->best_parent_rate) * req->best_parent_rate;
 if (rrate > hd->max_rate)
  rrate -= req->best_parent_rate;

 req->rate = rrate;
 return 0;
}

/*
 * For optimization reasons, assumes no downstream clocks are actively using
 * it.
 */

static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
         unsigned long parent_rate)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;
 unsigned long flags;
 u32 l_val, val;
 bool enabled;

 l_val = rate / parent_rate;

 spin_lock_irqsave(&h->lock, flags);

 enabled = __clk_is_enabled(hw->clk);
 if (enabled)
  __clk_hfpll_disable(h);

 /* Pick the right VCO. */
 if (hd->user_reg && hd->user_vco_mask) {
  regmap_read(regmap, hd->user_reg, &val);
  if (rate <= hd->low_vco_max_rate)
   val &= ~hd->user_vco_mask;
  else
   val |= hd->user_vco_mask;
  regmap_write(regmap, hd->user_reg, val);
 }

 regmap_write(regmap, hd->l_reg, l_val);

 if (enabled)
  __clk_hfpll_enable(hw);

 spin_unlock_irqrestore(&h->lock, flags);

 return 0;
}

static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
        unsigned long parent_rate)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;
 u32 l_val;

 regmap_read(regmap, hd->l_reg, &l_val);

 return l_val * parent_rate;
}

static int clk_hfpll_init(struct clk_hw *hw)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;
 u32 mode, status;

 regmap_read(regmap, hd->mode_reg, &mode);
 if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
  __clk_hfpll_init_once(hw);
  return 0;
 }

 if (hd->status_reg) {
  regmap_read(regmap, hd->status_reg, &status);
  if (!(status & BIT(hd->lock_bit))) {
   WARN(1, "HFPLL %s is ON, but not locked!\n",
        __clk_get_name(hw->clk));
   clk_hfpll_disable(hw);
   __clk_hfpll_init_once(hw);
  }
 }

 return 0;
}

static int hfpll_is_enabled(struct clk_hw *hw)
{
 struct clk_hfpll *h = to_clk_hfpll(hw);
 struct hfpll_data const *hd = h->d;
 struct regmap *regmap = h->clkr.regmap;
 u32 mode;

 regmap_read(regmap, hd->mode_reg, &mode);
 mode &= 0x7;
 return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
}

const struct clk_ops clk_ops_hfpll = {
 .enable = clk_hfpll_enable,
 .disable = clk_hfpll_disable,
 .is_enabled = hfpll_is_enabled,
 .determine_rate = clk_hfpll_determine_rate,
 .set_rate = clk_hfpll_set_rate,
 .recalc_rate = clk_hfpll_recalc_rate,
 .init = clk_hfpll_init,
};
EXPORT_SYMBOL_GPL(clk_ops_hfpll);

Messung V0.5
C=99 H=94 G=96

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© 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.