drivers/clk/spear/clk-gpt-synth.c

Source file repositories/reference/linux-study-clean/drivers/clk/spear/clk-gpt-synth.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/spear/clk-gpt-synth.c
Extension
.c
Size
3403 bytes
Lines
152
Domain
Driver Families
Bucket
drivers/clk
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2012 ST Microelectronics
 * Viresh Kumar <vireshk@kernel.org>
 *
 * General Purpose Timer Synthesizer clock implementation
 */

#define pr_fmt(fmt) "clk-gpt-synth: " fmt

#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include "clk.h"

#define GPT_MSCALE_MASK		0xFFF
#define GPT_NSCALE_SHIFT	12
#define GPT_NSCALE_MASK		0xF

/*
 * DOC: General Purpose Timer Synthesizer clock
 *
 * Calculates gpt synth clk rate for different values of mscale and nscale
 *
 * Fout= Fin/((2 ^ (N+1)) * (M+1))
 */

#define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw)

static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate,
		int index)
{
	struct clk_gpt *gpt = to_clk_gpt(hw);
	struct gpt_rate_tbl *rtbl = gpt->rtbl;

	prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1));

	return prate;
}

static int clk_gpt_determine_rate(struct clk_hw *hw,
				  struct clk_rate_request *req)
{
	struct clk_gpt *gpt = to_clk_gpt(hw);
	int unused;

	req->rate = clk_round_rate_index(hw, req->rate, req->best_parent_rate,
					 gpt_calc_rate, gpt->rtbl_cnt, &unused);

	return 0;
}

static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{
	struct clk_gpt *gpt = to_clk_gpt(hw);
	unsigned long flags = 0;
	unsigned int div = 1, val;

	if (gpt->lock)
		spin_lock_irqsave(gpt->lock, flags);

	val = readl_relaxed(gpt->reg);

	if (gpt->lock)
		spin_unlock_irqrestore(gpt->lock, flags);

	div += val & GPT_MSCALE_MASK;
	div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1);

	if (!div)
		return 0;

	return parent_rate / div;
}

/* Configures new clock rate of gpt */
static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate,
				unsigned long prate)
{
	struct clk_gpt *gpt = to_clk_gpt(hw);
	struct gpt_rate_tbl *rtbl = gpt->rtbl;
	unsigned long flags = 0, val;
	int i;

	clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt,
			&i);

	if (gpt->lock)

Annotation

Implementation Notes