clk_prepare()和clk_prepare_enable

问题引入

[ 7898.374645] ------------[ cut here ]------------
[ 7898.374837] WARNING: CPU: 2 PID: 1517 at drivers/clk/clk.c:730 clk_core_enable+0x94/0x)
[ 7898.375021] Modules linked in: timer(O+) [last unloaded: timer]
[ 7898.375285] CPU: 2 PID: 1517 Comm: insmod Tainted: G        W  O    4.4.0 #3
[ 7898.380949] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
[ 7898.387084] [] (unwind_backtrace) from [] (show_stack+0x10/0x14)
[ 7898.394786] [] (show_stack) from [] (dump_stack+0x80/0xc0)
[ 7898.401947] [] (dump_stack) from [] (warn_slowpath_common+0x80/0xb)
[ 7898.410016] [] (warn_slowpath_common) from [] (warn_slowpath_null+)
[ 7898.418781] [] (warn_slowpath_null) from [] (clk_core_enable+0x94/)
[ 7898.427116] [] (clk_core_enable) from [] (clk_enable+0x1c/0x38)
[ 7898.434760] [] (clk_enable) from [] (timer3_probe+0x5c/0x15c [time)
[ 7898.442921] [] (timer3_probe [timer]) from [] (platform_drv_probe+)
[ 7898.451680] [] (platform_drv_probe) from [] (driver_probe_device+0)
[ 7898.460532] [] (driver_probe_device) from [] (__driver_attach+0x8c)
[ 7898.468959] [] (__driver_attach) from [] (bus_for_each_dev+0x60/0x)
[ 7898.477115] [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x)
[ 7898.485358] [] (bus_add_driver) from [] (driver_register+0x78/0xf8)
[ 7898.493346] [] (driver_register) from [] (timer_init+0x10/0x3c [ti)
[ 7898.501681] [] (timer_init [timer]) from [] (do_one_initcall+0x90/)
[ 7898.510100] [] (do_one_initcall) from [] (do_init_module+0x60/0x34)
[ 7898.518172] [] (do_init_module) from [] (load_module+0x1b3c/0x1d68)
[ 7898.526153] [] (load_module) from [] (SyS_init_module+0xd4/0x144)
[ 7898.533967] [] (SyS_init_module) from [] (ret_fast_syscall+0x0/0x3)
[ 7898.542031] ---[ end trace 655de26992d22f14 ]---
[ 7898.546682] ret:-108

最近写驱动时ret=clk_enable(clk)报错,追溯原因:
http://blog.csdn.net/qq_33160790/article/details/79354855
108对应着ESHUTDOWN,所以出错是因为
clk_prepare()和clk_prepare_enable_第1张图片
后来查阅资料,在使用clk_enable之前调用clk_prepare,或者使用clk_prepare_enable API即可。


clk_prepare()和clk_prepare_enable

/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
static inline int clk_prepare_enable(struct clk *clk)
{
        int ret;

        ret = clk_prepare(clk);
        if (ret)
                return ret;
        ret = clk_enable(clk);
        if (ret)        
                clk_unprepare(clk);

        return ret;
}

很明显clk_prepare_enable就是把clk_prepare和clk_enable封装在一起。
早期的驱动中,并没有clk_prepare这个API,带prepare关键字的都是新加入的。

值得一提的是,名称中含有prepare、unprepare字符串的API是内核后来才加入的,过去
只有clk_enable和clk_disable。只有clk_enable和clk_disable带来的问题是,
有时候,某些硬件的enable/disable clk可能引起睡眠使得enable/disable不能在原子
上下文进行。
加上prepare后,把过去的clk_enable分解成不可在原子上下文调用的
clk_prepare(该函数可能睡眠)和可以在原子上下文调用的clk_enable。
而clk_prepare_enable则同时完成
prepare和enable的工作,当然也只能在可能睡眠的上下文调用该API。

怎么理解上面这段话呢,我觉得关键点在于clk_prepare为什么可能睡眠。
clk_prepare()和clk_prepare_enable_第2张图片

你可能感兴趣的:(Linux,CLK)