drivers/clk/ingenic/cgu.c
Source file repositories/reference/linux-study-clean/drivers/clk/ingenic/cgu.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/clk/ingenic/cgu.c- Extension
.c- Size
- 21534 bytes
- Lines
- 854
- 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.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- 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/bitops.hlinux/clk.hlinux/clk-provider.hlinux/clkdev.hlinux/delay.hlinux/io.hlinux/iopoll.hlinux/math64.hlinux/of.hlinux/of_address.hlinux/slab.hlinux/spinlock.hlinux/time.hcgu.h
Detected Declarations
function Copyrightfunction ingenic_cgu_gate_getfunction ingenic_cgu_gate_setfunction ingenic_pll_recalc_ratefunction ingenic_pll_calc_m_n_odfunction ingenic_pll_calcfunction ingenic_pll_determine_ratefunction ingenic_pll_check_stablefunction ingenic_pll_set_ratefunction ingenic_pll_enablefunction ingenic_pll_disablefunction ingenic_pll_is_enabledfunction ingenic_clk_get_parentfunction ingenic_clk_set_parentfunction ingenic_clk_recalc_ratefunction ingenic_clk_calc_hw_divfunction ingenic_clk_calc_divfunction ingenic_clk_determine_ratefunction ingenic_clk_check_stablefunction ingenic_clk_set_ratefunction ingenic_clk_enablefunction ingenic_clk_disablefunction ingenic_clk_is_enabledfunction ingenic_register_clockfunction ingenic_cgu_newfunction ingenic_cgu_register_clocks
Annotated Snippet
if (!(clk_info->div.bypass_mask & BIT(parent))) {
div_reg = readl(cgu->base + clk_info->div.reg);
div = (div_reg >> clk_info->div.shift) &
GENMASK(clk_info->div.bits - 1, 0);
if (clk_info->div.div_table)
div = clk_info->div.div_table[div];
else
div = (div + 1) * clk_info->div.div;
rate /= div;
}
} else if (clk_info->type & CGU_CLK_FIXDIV) {
rate /= clk_info->fixdiv.div;
}
return rate;
}
static unsigned int
ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
unsigned int div)
{
unsigned int i, best_i = 0, best = (unsigned int)-1;
for (i = 0; i < (1 << clk_info->div.bits)
&& clk_info->div.div_table[i]; i++) {
if (clk_info->div.div_table[i] >= div &&
clk_info->div.div_table[i] < best) {
best = clk_info->div.div_table[i];
best_i = i;
if (div == best)
break;
}
}
return best_i;
}
static unsigned
ingenic_clk_calc_div(struct clk_hw *hw,
const struct ingenic_cgu_clk_info *clk_info,
unsigned long parent_rate, unsigned long req_rate)
{
unsigned int div, hw_div;
u8 parent;
parent = ingenic_clk_get_parent(hw);
if (clk_info->div.bypass_mask & BIT(parent))
return 1;
/* calculate the divide */
div = DIV_ROUND_UP(parent_rate, req_rate);
if (clk_info->div.div_table) {
hw_div = ingenic_clk_calc_hw_div(clk_info, div);
return clk_info->div.div_table[hw_div];
}
/* Impose hardware constraints */
div = clamp_t(unsigned int, div, clk_info->div.div,
clk_info->div.div << clk_info->div.bits);
/*
* If the divider value itself must be divided before being written to
* the divider register, we must ensure we don't have any bits set that
* would be lost as a result of doing so.
*/
div = DIV_ROUND_UP(div, clk_info->div.div);
div *= clk_info->div.div;
return div;
}
static int ingenic_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
unsigned int div = 1;
if (clk_info->type & CGU_CLK_DIV)
div = ingenic_clk_calc_div(hw, clk_info, req->best_parent_rate,
req->rate);
else if (clk_info->type & CGU_CLK_FIXDIV)
div = clk_info->fixdiv.div;
else if (clk_hw_can_set_rate_parent(hw))
req->best_parent_rate = req->rate;
Annotation
- Immediate include surface: `linux/bitops.h`, `linux/clk.h`, `linux/clk-provider.h`, `linux/clkdev.h`, `linux/delay.h`, `linux/io.h`, `linux/iopoll.h`, `linux/math64.h`.
- Detected declarations: `function Copyright`, `function ingenic_cgu_gate_get`, `function ingenic_cgu_gate_set`, `function ingenic_pll_recalc_rate`, `function ingenic_pll_calc_m_n_od`, `function ingenic_pll_calc`, `function ingenic_pll_determine_rate`, `function ingenic_pll_check_stable`, `function ingenic_pll_set_rate`, `function ingenic_pll_enable`.
- Atlas domain: Driver Families / drivers/clk.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
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.