#include #include #include #include #include static struct clk *clk; static struct notifier_block nb; static int clk_notif_dbg_cb(struct notifier_block *nb, unsigned long event, void *data) { pr_info("clk_notif_dbg_cb\n"); return NOTIFY_OK; } static int clk_notif_dbg_probe(struct platform_device *pdev) { nb.next = NULL; nb.notifier_call = clk_notif_dbg_cb; dev_info(&pdev->dev, "clk_get()\n"); clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "clk_get failed\n"); return PTR_ERR(clk); } dev_info(&pdev->dev, "clk_prepare()\n"); if (clk_prepare(clk)) dev_warn(&pdev->dev, "clk_prepare failed\n"); dev_info(&pdev->dev, "clk_enable()\n"); if (clk_enable(clk)) dev_warn(&pdev->dev, "clk_enable failed\n"); dev_info(&pdev->dev, "clk_notifier_register()\n"); if (clk_notifier_register(clk, &nb)) dev_warn(&pdev->dev, "clk_notifier_register failed\n"); dev_info(&pdev->dev, "probe done\n"); return 0; } static int clk_notif_dbg_remove(struct platform_device *pdev) { dev_info(&pdev->dev, "clk_notifier_unregister()\n"); clk_notifier_unregister(clk, &nb); dev_info(&pdev->dev, "clk_disable()\n"); clk_disable(clk); dev_info(&pdev->dev, "clk_unprepare()\n"); clk_unprepare(clk); dev_info(&pdev->dev, "clk_put()\n"); clk_put(clk); dev_info(&pdev->dev, "remove done\n"); return 0; } /* Match table for device tree binding */ static const struct of_device_id clk_notif_dbg_of_match[] = { {.compatible = "clk_notif_dbg"}, { }, }; MODULE_DEVICE_TABLE(of, clk_notif_dbg_of_match); static struct platform_driver clk_notif_dbg_driver = { .probe = clk_notif_dbg_probe, .remove = clk_notif_dbg_remove, .driver = { .name = "clk_notif_dbg", .owner = THIS_MODULE, .of_match_table = clk_notif_dbg_of_match, }, }; module_platform_driver(clk_notif_dbg_driver); MODULE_AUTHOR("Xilinx, Inc."); MODULE_DESCRIPTION("Clock notifier debug"); MODULE_LICENSE("GPL");