An Analysis of clock registration for Linux Device Drivers

Source: Internet
Author: User

When using the embedded Linux driver, clock is inevitable. I checked the clock information online today and found that most of the information on the Internet is about the clock mechanism of the Linux kernel, not the clock of the Linux Device Driver.

So I wrote out my learning experience today and communicated with you. I hope the experts will point out something wrong.

I will take Samsung's smdkc220 Development Board as an example.

Analyze the code. It also regards clock as a device. Register it before use, but this register is different from the general device and will not be used under sysfs, generate a node in a directory such as driver or bus.

First look at the register function exynos4_register_clocks (void), in the arch \ Arm \ Mach-exynos \ Clock-exynos4.c file,

Void _ init exynos4_register_clocks (void)
{

// ...... Omitted

Initi_register_clksrc (exynos4_clksrcs, array_size (exynos4_clksrcs ));
Initi_register_clocks (exynos4_init_clocks, array_size (exynos4_init_clocks ));

Initi_register_clocks (exynos4_init_clocks_off, array_size (exynos4_init_clocks_off ));
Initi_disable_clocks (exynos4_init_clocks_off, array_size (exynos4_init_clocks_off ));

Initi_register_clocks (exynos4_init_audss_clocks, array_size (exynos4_init_audss_clocks ));
S3_disable_clocks (exynos4_init_audss_clocks, array_size (exynos4_init_audss_clocks ));

// ...... Omitted

Initi_pwmclk_init ();
}


Samsung classifies clock by device, such as JPEG, fimc, mipi-CSI, and mipi-DSI, into the exynos4_init_clocks_off array, such as the exynos4_clksrcs array, is a variety of source CLK.

Regardless of the register functions above, they are essentially the same, but they use different names for clock registration for different classes.


Before executing register, you must define the clock, that is, the content of each array.

Take exynos4_init_clocks_off as an example,

Static struct CLK exynos4_init_clocks_off [] = {

//... Omitted

{
. Name = "CSIS ",
. Devname
= "S3c-csis.0 ",
. Enable
= Exynos4_clk_ip_cam_ctrl,
. Ctrlbit
= (1 <4 ),

},{
. Name = "fimc ",
. Devname
= "S3c-fimc.0 ",
. Enable
= Exynos4_clk_ip_cam_ctrl,
. Ctrlbit
= (1 <0 ),

},{
. Name = "Jpeg ",
. Enable
= Exynos4_clk_ip_cam_ctrl,
. Ctrlbit
= (1 <11) | (1 <6 )),

},{
. Name = "dsim0 ",
. Enable
= Exynos4_clk_ip_lcd0_ctrl,
. Ctrlbit
= (1 <3 ),
}

// ...... Omitted

}


Here, we define the CLK of JPEG, fimc, mipi-DSI, and mipi-CSI, and return their clock names (. name), enable function, also pointed out in the clock control register which is to control their respective (ctrlbit ). But although registered here, Samsung also recently added a devname this stuff, this refers to the device name, such as fimc the device name is s3c-fimc.0, however, its clock name is "fimc ". Be sure to differentiate the two. It will be used when registering a device in the future (Registration of clock is performed before registration of the device ).


Next, let's take a closer look at how to register.

Void _ init 89c_register_clocks (struct CLK * clkp, int nr_clks)
{
Int ret;

For (; nr_clks> 0; nr_clks --, clkp ++ ){
Ret = s3c24xx_register_clock (clkp );

If (Ret <0 ){
Printk (kern_err "failed to register clock % s (% d) \ n ",
Clkp-> name, RET );
}
}
}


Recall that the exynos4_init_clocks_off [] array defines the clock of some devices. Pass in the array through the clkp parameter, and use a for loop to register the clock of each device.

Here, we call s3c24xx_register_clock (clkp) to register the clock of a device. After registration, the pointer ++ points to the device's clock.


Int s3c24xx_register_clock (struct CLK * CLK)
{
If (CLK-> enable = NULL)
CLK-> enable = clk_null_enable;

/* Fill up the clk_lookup structure and register it */
CLK-> lookup. dev_id = CLK-> devname;
CLK-> lookup. con_id = CLK-> name;
CLK-> lookup. CLK = CLK;
Clkdev_add (& CLK-> lookup );

Return 0;
}

Check this registration function. First, check whether there is an enable function in the previously defined device clock. If not, give it an empty, non-real empty function.

Then, remember that the clock name and device name were returned when the clock was just defined? Copy the two names to the member variables of the lookup struct In the CLK struct respectively.

Here, let's take a look at the CLK struct. Samsung defined it in this way, which is different from that in Linux.


Struct CLK {
Struct list_head list;
Struct module * owner;
Struct CLK * parent;
Const char * Name;
Const char
* Devname;
Int ID;
Int usage;
Unsigned long rate;
Unsigned long ctrlbit;

Struct clk_ops * OPS;
INT (* enable) (struct CLK *, int enable );
Struct clk_lookuplookup;
# If defined (config_pm_debug) & defined (config_debug_fs)
Struct dentry
* Dent;/* for visible tree hierarchy */
# Endif
};

When I defined the device's clock, I gave the name, devname, enable, and ctrlbit. However, other members are still blank and will be filled in later.

Now let's take a look at the clk_lookup struct. What is the purpose of this member?

As the name suggests, lookup is definitely used for search. So when can we find it? What can we find?

Here, we separate the registered device from the registered device's clock. The registered device's clock is completed once, and the various device's clock is registered once, however, our device registration is performed individually.

Therefore, when registering a device, you need to find your own clock in the previously registered clock stack. At this time, the clk_lookup structure is required.


Struct clk_lookup {
Struct list_headnode;
Const char
* Dev_id;
Const char
* Con_id;
Struct CLK
* CLK;
};

In this structure, there are two members: dev_id and con_id, which represent clock name and device name. Therefore, we need to copy the clock name and device name to the two members. So there is

CLK-> lookup. dev_id = CLK-> devname;
CLK-> lookup. con_id = CLK-> name;

Then CLK-> lookup. CLK = CLK; the same is true.

Let's look back at clkdev_add (& CLK-> lookup). What does this sentence mean?

Let's talk about how to find our own clock in the clock heap when registering a device. Is through a clock chain (listhead), which is a bidirectional loop chain. What are the nodes of this chain?

Is the clk_lookup struct!

Now we know that each clk_lookup contains some simple information (name, devname) about each device. This information is rich enough to separate different clk_lookup structures.

Clkdev_add (& CLK-> lookup); this sentence means to use the clk_lookup struct as a node and connect it to the tail of the chain.

You can see the details of it,

Void clkdev_add (struct clk_lookup * cl)
{
Mutex_lock (& clocks_mutex );
List_add_tail (& CL-> node, & clocks );
Mutex_unlock (& clocks_mutex );
}

As the name implies, list_add_tail is added to the tail.

Then we need to link a piece of things to a chain, so there should be a small hook or something else on it ~

This is the node member variable in clk_lookup (in the above function, it is cl-> node)

What is this node? Let's see its definition in clk_lookup:

Struct list_head
Node;

We know that the list_head structure is like a small hook in front and a small hook in the back. Many list_head hooks each other through small hooks, forming a chain.

Therefore, different clk_lookup struct are connected to each other through node to form a chain.

The chain is as follows:

Clk_lookup1 clk_lookup2 clk_lookup3

... ------ Node1 ----------- node2 ------------------- node3 ----------....

|

* Name1 * name2 * name3

|

* Devname1 * devname2 * devname3

|

.........


This chain is defined at the beginning. We use static list_head (clocks); to define a static empty chain for all users. Then a node is connected up from one node.

After the clk_lookup struct is connected to the chain, that is, the clock of each device is connected to the chain. Why? Because the clk_lookup struct contains a member variable named CLK. It is clock.

So far, we have completed registration.

What is the purpose of registration?

I think, it is to form a chain that allows you to search for a device later.




The younger brother's knowledge is simple. Please point out the incorrect information. You are also welcome to join us. Mailbox alvinlee910@hotmail.com. Indicate the source for reprinting.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.