Fundamentals 8 min read

How to Identify and Control Module Clock Sources in the Exynos4 Linux Kernel

This article explains how embedded Linux on Exynos4 determines which peripheral clocks are enabled or disabled, describes the struct clk representation, shows the registration process in Clock‑exynos4.c, and provides the APIs (clk_get, clk_enable, clk_disable, etc.) for querying and managing module clocks such as the LCD controller.

ITPUB
ITPUB
ITPUB
How to Identify and Control Module Clock Sources in the Exynos4 Linux Kernel

In low‑power embedded systems only the clocks required by active peripherals are turned on, while unused modules remain disabled. The LCD controller (fimd0) is powered off by default, so its clock must be enabled before the LCD can be used.

Clock representation in the kernel

The kernel describes each peripheral’s clock with a struct clk defined in Clock-exynos4.c (path arch/arm/mach-exynos).

struct clk {
    struct list_head      list;
    struct module        *owner;
    struct clk           *parent;
    const char           *name;
    const char           *devname; // device name for lookup
    int                  id;
    int                  usage;
    unsigned long        rate;
    unsigned long        ctrlbit;
    struct clk_ops       *ops;
    int (*enable)(struct clk *, int enable);
    struct clk_lookup    lookup;
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
    struct dentry        *dent; // visible tree hierarchy
#endif
};

The registration of all clocks occurs in the exynos4_register_clocks() function, which calls helper functions such as s3c24xx_register_clocks() and s3c_register_clksrc(). The LCD clock (fimd0) is registered here and then explicitly disabled to save power.

void __init exynos4_register_clocks(void)
{
    int ptr;
    s3c24xx_register_clocks(exynos4_clks, ARRAY_SIZE(exynos4_clks));
    for (ptr = 0; ptr < ARRAY_SIZE(exynos4_sysclks); ptr++)
        s3c_register_clksrc(exynos4_sysclks[ptr], 1);
    // ... other registrations ...
    // Register LCD clock (fimd0)
    s3c24xx_register_clocks(exynos4_clk_cdev, ARRAY_SIZE(exynos4_clk_cdev));
    // Disable it after registration to reduce power consumption
    for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clk_cdev); ptr++)
        s3c_disable_clocks(exynos4_clk_cdev[ptr], 1);
    // Add lookup table for clk_get
    Clkdev_add_table(exynos4_clk_lookup, ARRAY_SIZE(exynos4_clk_lookup));
}

Clock lookup mechanism

After registration, clkdev_add_table() inserts entries into a searchable list. Each entry is a struct clk_lookup :

struct clk_lookup {
    struct list_head node;
    const char *dev_id; // device name used for lookup
    const char *con_id; // connection name (bus) used for lookup
    struct clk *clk;    // pointer to the associated struct clk
};

The macro CLKDEV_INIT simplifies creating these entries. For the LCD controller the entry looks like:

#define CLKDEV_INIT(d, n, c) { .dev_id = d, .con_id = n, .clk = c }
static struct clk_lookup exynos4_clk_lookup[] = {
    // ... other entries ...
    CLKDEV_INIT("exynos4-fb.0", "lcd", &exynos4_clk_fimd0),
};

Runtime API for clocks

Kernel code can obtain a clock structure with:

struct clk *clk_get(struct device *dev, const char *id);

The function matches dev->init_name with dev_id and id with con_id. It returns a pointer on success or an error pointer (checked with IS_ERR()) on failure.

Typical usage:

s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
if (IS_ERR(s3c_ac97.ac97_clk)) {
    dev_err(&pdev->dev, "ac97 failed to get ac97_clock
");
    ret = -ENODEV;
    goto err2;
}
clk_enable(s3c_ac97.ac97_clk);

Once a struct clk is obtained, the following operations are available: int clk_enable(struct clk *clk); – enable the clock (returns 0 on success). void clk_disable(struct clk *clk); – disable the clock to save power. unsigned long clk_get_rate(struct clk *clk); – read the current frequency in Hz. int clk_set_rate(struct clk *clk, unsigned long rate); – set a new frequency (returns 0 on success). void clk_put(struct clk *clk); – decrement the usage count when the clock is no longer needed.

These APIs are declared in include/linux/clk.h (Linux 3.5) and are generic across platforms, allowing driver code to manage peripheral clocks without hard‑coding hardware details.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Linux kernelembedded systemsDevice DriversClock ManagementExynos4
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.