drivers/clk/mstar/clk-msc313-cpupll.c
Source file repositories/reference/linux-study-clean/drivers/clk/mstar/clk-msc313-cpupll.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/clk/mstar/clk-msc313-cpupll.c- Extension
.c- Size
- 6528 bytes
- Lines
- 223
- 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.
- 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.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/clk-provider.hlinux/device.hlinux/kernel.hlinux/of_address.hlinux/platform_device.h
Detected Declarations
struct msc313_cpupllfunction msc313_cpupll_reg_read32function msc313_cpupll_reg_write32function msc313_cpupll_setfreqfunction msc313_cpupll_frequencyforregfunction msc313_cpupll_regforfrequecyfunction msc313_cpupll_recalc_ratefunction msc313_cpupll_determine_ratefunction msc313_cpupll_set_ratefunction msc313_cpupll_probe
Annotated Snippet
struct msc313_cpupll {
void __iomem *base;
struct clk_hw clk_hw;
};
#define to_cpupll(_hw) container_of(_hw, struct msc313_cpupll, clk_hw)
static u32 msc313_cpupll_reg_read32(struct msc313_cpupll *cpupll, unsigned int reg)
{
u32 value;
value = ioread16(cpupll->base + reg + 4) << 16;
value |= ioread16(cpupll->base + reg);
return value;
}
static void msc313_cpupll_reg_write32(struct msc313_cpupll *cpupll, unsigned int reg, u32 value)
{
u16 l = value & 0xffff, h = (value >> 16) & 0xffff;
iowrite16(l, cpupll->base + reg);
iowrite16(h, cpupll->base + reg + 4);
}
static void msc313_cpupll_setfreq(struct msc313_cpupll *cpupll, u32 regvalue)
{
ktime_t timeout;
msc313_cpupll_reg_write32(cpupll, REG_LPF_HIGH_BOTTOM, regvalue);
iowrite16(0x1, cpupll->base + REG_LPF_MYSTERYONE);
iowrite16(0x6, cpupll->base + REG_LPF_MYSTERYTWO);
iowrite16(0x8, cpupll->base + REG_LPF_UPDATE_COUNT);
iowrite16(BIT(12), cpupll->base + REG_LPF_TRANSITIONCTRL);
iowrite16(0, cpupll->base + REG_LPF_TOGGLE);
iowrite16(1, cpupll->base + REG_LPF_TOGGLE);
timeout = ktime_add_ns(ktime_get(), LPF_LOCK_TIMEOUT);
while (!(ioread16(cpupll->base + REG_LPF_LOCK))) {
if (ktime_after(ktime_get(), timeout)) {
pr_err("timeout waiting for LPF_LOCK\n");
return;
}
cpu_relax();
}
iowrite16(0, cpupll->base + REG_LPF_TOGGLE);
msc313_cpupll_reg_write32(cpupll, REG_LPF_LOW_L, regvalue);
}
static unsigned long msc313_cpupll_frequencyforreg(u32 reg, unsigned long parent_rate)
{
unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER;
if (prescaled == 0 || reg == 0)
return 0;
return DIV_ROUND_DOWN_ULL(prescaled, reg);
}
static u32 msc313_cpupll_regforfrequecy(unsigned long rate, unsigned long parent_rate)
{
unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER;
if (prescaled == 0 || rate == 0)
return 0;
return DIV_ROUND_UP_ULL(prescaled, rate);
}
static unsigned long msc313_cpupll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
struct msc313_cpupll *cpupll = to_cpupll(hw);
return msc313_cpupll_frequencyforreg(msc313_cpupll_reg_read32(cpupll, REG_LPF_LOW_L),
parent_rate);
}
static int msc313_cpupll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
u32 reg = msc313_cpupll_regforfrequecy(req->rate, req->best_parent_rate);
long rounded = msc313_cpupll_frequencyforreg(reg, req->best_parent_rate);
/*
* This is my poor attempt at making sure the resulting
* rate doesn't overshoot the requested rate.
*/
for (; rounded >= req->rate && reg > 0; reg--)
Annotation
- Immediate include surface: `linux/clk-provider.h`, `linux/device.h`, `linux/kernel.h`, `linux/of_address.h`, `linux/platform_device.h`.
- Detected declarations: `struct msc313_cpupll`, `function msc313_cpupll_reg_read32`, `function msc313_cpupll_reg_write32`, `function msc313_cpupll_setfreq`, `function msc313_cpupll_frequencyforreg`, `function msc313_cpupll_regforfrequecy`, `function msc313_cpupll_recalc_rate`, `function msc313_cpupll_determine_rate`, `function msc313_cpupll_set_rate`, `function msc313_cpupll_probe`.
- Atlas domain: Driver Families / drivers/clk.
- Implementation status: source implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.