drivers/clk/sunxi/clk-sun9i-cpus.c
Source file repositories/reference/linux-study-clean/drivers/clk/sunxi/clk-sun9i-cpus.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/clk/sunxi/clk-sun9i-cpus.c- Extension
.c- Size
- 6370 bytes
- Lines
- 244
- 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/clk.hlinux/clk-provider.hlinux/io.hlinux/slab.hlinux/spinlock.hlinux/of.hlinux/of_address.h
Detected Declarations
struct sun9i_a80_cpus_clkfunction sun9i_a80_cpus_clk_recalc_ratefunction sun9i_a80_cpus_clk_roundfunction sun9i_a80_cpus_clk_determine_ratefunction sun9i_a80_cpus_clk_set_ratefunction sun9i_a80_cpus_setup
Annotated Snippet
struct sun9i_a80_cpus_clk {
struct clk_hw hw;
void __iomem *reg;
};
#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
unsigned long rate;
u32 reg;
/* Fetch the register value */
reg = readl(cpus->reg);
/* apply pre-divider first if parent is pll4 */
if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
/* clk divider */
rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
return rate;
}
static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
u8 parent, unsigned long parent_rate)
{
u8 div, pre_div = 1;
/*
* clock can only divide, so we will never be able to achieve
* frequencies higher than the parent frequency
*/
if (parent_rate && rate > parent_rate)
rate = parent_rate;
div = DIV_ROUND_UP(parent_rate, rate);
/* calculate pre-divider if parent is pll4 */
if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
/* pre-divider is 1 ~ 32 */
if (div < 32) {
pre_div = div;
div = 1;
} else if (div < 64) {
pre_div = DIV_ROUND_UP(div, 2);
div = 2;
} else if (div < 96) {
pre_div = DIV_ROUND_UP(div, 3);
div = 3;
} else {
pre_div = DIV_ROUND_UP(div, 4);
div = 4;
}
}
/* we were asked to pass back divider values */
if (divp) {
*divp = div - 1;
*pre_divp = pre_div - 1;
}
return parent_rate / pre_div / div;
}
static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
struct clk_rate_request *req)
{
struct clk_hw *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
unsigned long rate = req->rate;
/* find the parent that can help provide the fastest rate <= rate */
num_parents = clk_hw_get_num_parents(clk);
for (i = 0; i < num_parents; i++) {
parent = clk_hw_get_parent_by_index(clk, i);
if (!parent)
continue;
if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
parent_rate = clk_hw_round_rate(parent, rate);
else
parent_rate = clk_hw_get_rate(parent);
child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
parent_rate);
Annotation
- Immediate include surface: `linux/clk.h`, `linux/clk-provider.h`, `linux/io.h`, `linux/slab.h`, `linux/spinlock.h`, `linux/of.h`, `linux/of_address.h`.
- Detected declarations: `struct sun9i_a80_cpus_clk`, `function sun9i_a80_cpus_clk_recalc_rate`, `function sun9i_a80_cpus_clk_round`, `function sun9i_a80_cpus_clk_determine_rate`, `function sun9i_a80_cpus_clk_set_rate`, `function sun9i_a80_cpus_setup`.
- 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.