drivers/clk/renesas/r9a09g077-cpg.c
Source file repositories/reference/linux-study-clean/drivers/clk/renesas/r9a09g077-cpg.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/clk/renesas/r9a09g077-cpg.c- Extension
.c- Size
- 16555 bytes
- Lines
- 519
- 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/bitfield.hlinux/clk-provider.hlinux/device.hlinux/init.hlinux/kernel.hlinux/math.hlinux/types.hdt-bindings/clock/renesas,r9a09g077-cpg-mssr.hdt-bindings/clock/renesas,r9a09g087-cpg-mssr.hrenesas-cpg-mssr.h
Detected Declarations
enum rzt2h_clk_typesenum clk_idsfunction r9a09g077_cpg_div_clk_registerfunction r9a09g077_cpg_mux_clk_registerfunction r9a09g077_cpg_fselxspi_get_dividerfunction r9a09g077_cpg_fselxspi_determine_ratefunction r9a09g077_cpg_fselxspi_div_clk_registerfunction r9a09g077_cpg_clk_register
Annotated Snippet
if (best_rate == rate) {
ff = to_clk_fixed_factor(parent_hw);
return ff->div;
}
}
/* No parent could provide the exact rate - this should not happen */
return 0;
}
static int r9a09g077_cpg_fselxspi_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_divider *divider = to_clk_divider(hw);
unsigned long parent_rate, best = 0, now;
const struct clk_div_table *clkt;
unsigned long rate = req->rate;
unsigned int num_parents;
unsigned int divselxspi;
unsigned int div = 0;
if (!rate)
rate = 1;
/* Get the number of parents for FSELXSPIn */
num_parents = clk_hw_get_num_parents(req->best_parent_hw);
for (clkt = divider->table; clkt->div; clkt++) {
parent_rate = clk_hw_round_rate(req->best_parent_hw, rate * clkt->div);
/* Skip if parent can't provide any valid rate */
if (!parent_rate)
continue;
/* Determine which DIVSELXSPIn divider (3 or 4) provides this parent_rate */
divselxspi = r9a09g077_cpg_fselxspi_get_divider(req->best_parent_hw, parent_rate,
num_parents);
if (!divselxspi)
continue;
/*
* DIVSELXSPIx supports 800MHz and 600MHz operation.
* When divselxspi is 4 (600MHz operation), only FSELXSPIn dividers of 8 and 16
* are supported. Otherwise, when divselxspi is 3 (800MHz operation),
* dividers of 6, 8, 16, 32, and 64 are supported. This check ensures that
* FSELXSPIx is set correctly based on hardware limitations.
*/
if (divselxspi == 4 && (clkt->div != 8 && clkt->div != 16))
continue;
now = DIV_ROUND_UP_ULL(parent_rate, clkt->div);
if (abs(rate - now) < abs(rate - best)) {
div = clkt->div;
best = now;
req->best_parent_rate = parent_rate;
}
}
if (!div) {
req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw, 1);
divselxspi = r9a09g077_cpg_fselxspi_get_divider(req->best_parent_hw,
req->best_parent_rate,
num_parents);
/* default to divider 3 which will result DIVSELXSPIn = 800 MHz */
if (!divselxspi)
divselxspi = 3;
/*
* Use the maximum divider based on the parent clock rate:
* - 64 when DIVSELXSPIx is 800 MHz (divider = 3)
* - 16 when DIVSELXSPIx is 600 MHz (divider = 4)
*/
div = divselxspi == 3 ? 64 : 16;
}
req->rate = DIV_ROUND_UP_ULL(req->best_parent_rate, div);
return 0;
}
static struct clk * __init
r9a09g077_cpg_fselxspi_div_clk_register(struct device *dev,
const struct cpg_core_clk *core,
void __iomem *addr,
struct cpg_mssr_pub *pub)
{
static struct clk_ops *xspi_div_ops;
struct clk_init_data init = {};
const struct clk *parent;
const char *parent_name;
struct clk_divider *div;
Annotation
- Immediate include surface: `linux/bitfield.h`, `linux/clk-provider.h`, `linux/device.h`, `linux/init.h`, `linux/kernel.h`, `linux/math.h`, `linux/types.h`, `dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h`.
- Detected declarations: `enum rzt2h_clk_types`, `enum clk_ids`, `function r9a09g077_cpg_div_clk_register`, `function r9a09g077_cpg_mux_clk_register`, `function r9a09g077_cpg_fselxspi_get_divider`, `function r9a09g077_cpg_fselxspi_determine_rate`, `function r9a09g077_cpg_fselxspi_div_clk_register`, `function r9a09g077_cpg_clk_register`.
- 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.