clk_prepare()和clk_prepare_enable

本文解析了在驱动开发中遇到的clk_enable错误及其原因,并介绍了如何通过使用clk_prepare_enable API来解决这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题引入

[ 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] [<c00160ec>] (unwind_backtrace) from [<c0012e08>] (show_stack+0x10/0x14)
[ 7898.394786] [<c0012e08>] (show_stack) from [<c01f6bd8>] (dump_stack+0x80/0xc0)
[ 7898.401947] [<c01f6bd8>] (dump_stack) from [<c00235c8>] (warn_slowpath_common+0x80/0xb)
[ 7898.410016] [<c00235c8>] (warn_slowpath_common) from [<c0023694>] (warn_slowpath_null+)
[ 7898.418781] [<c0023694>] (warn_slowpath_null) from [<c04092c4>] (clk_core_enable+0x94/)
[ 7898.427116] [<c04092c4>] (clk_core_enable) from [<c04095e0>] (clk_enable+0x1c/0x38)
[ 7898.434760] [<c04095e0>] (clk_enable) from [<bf02c07c>] (timer3_probe+0x5c/0x15c [time)
[ 7898.442921] [<bf02c07c>] (timer3_probe [timer]) from [<c02c58c4>] (platform_drv_probe+)
[ 7898.451680] [<c02c58c4>] (platform_drv_probe) from [<c02c3f54>] (driver_probe_device+0)
[ 7898.460532] [<c02c3f54>] (driver_probe_device) from [<c02c40a0>] (__driver_attach+0x8c)
[ 7898.468959] [<c02c40a0>] (__driver_attach) from [<c02c247c>] (bus_for_each_dev+0x60/0x)
[ 7898.477115] [<c02c247c>] (bus_for_each_dev) from [<c02c366c>] (bus_add_driver+0x1a0/0x)
[ 7898.485358] [<c02c366c>] (bus_add_driver) from [<c02c4874>] (driver_register+0x78/0xf8)
[ 7898.493346] [<c02c4874>] (driver_register) from [<bf02c18c>] (timer_init+0x10/0x3c [ti)
[ 7898.501681] [<bf02c18c>] (timer_init [timer]) from [<c0009774>] (do_one_initcall+0x90/)
[ 7898.510100] [<c0009774>] (do_one_initcall) from [<c0098050>] (do_init_module+0x60/0x34)
[ 7898.518172] [<c0098050>] (do_init_module) from [<c008bef0>] (load_module+0x1b3c/0x1d68)
[ 7898.526153] [<c008bef0>] (load_module) from [<c008c1f0>] (SyS_init_module+0xd4/0x144)
[ 7898.533967] [<c008c1f0>] (SyS_init_module) from [<c000f600>] (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_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为什么可能睡眠。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值