Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
0004  * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
0005  *
0006  * Fixed rate clock implementation
0007  */
0008 
0009 #include <linux/clk-provider.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/io.h>
0013 #include <linux/err.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 
0017 /*
0018  * DOC: basic fixed-rate clock that cannot gate
0019  *
0020  * Traits of this clock:
0021  * prepare - clk_(un)prepare only ensures parents are prepared
0022  * enable - clk_enable only ensures parents are enabled
0023  * rate - rate is always a fixed value.  No clk_set_rate support
0024  * parent - fixed parent.  No clk_set_parent support
0025  */
0026 
0027 #define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
0028 
0029 static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
0030         unsigned long parent_rate)
0031 {
0032     return to_clk_fixed_rate(hw)->fixed_rate;
0033 }
0034 
0035 static unsigned long clk_fixed_rate_recalc_accuracy(struct clk_hw *hw,
0036         unsigned long parent_accuracy)
0037 {
0038     struct clk_fixed_rate *fixed = to_clk_fixed_rate(hw);
0039 
0040     if (fixed->flags & CLK_FIXED_RATE_PARENT_ACCURACY)
0041         return parent_accuracy;
0042 
0043     return fixed->fixed_accuracy;
0044 }
0045 
0046 const struct clk_ops clk_fixed_rate_ops = {
0047     .recalc_rate = clk_fixed_rate_recalc_rate,
0048     .recalc_accuracy = clk_fixed_rate_recalc_accuracy,
0049 };
0050 EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
0051 
0052 struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev,
0053         struct device_node *np, const char *name,
0054         const char *parent_name, const struct clk_hw *parent_hw,
0055         const struct clk_parent_data *parent_data, unsigned long flags,
0056         unsigned long fixed_rate, unsigned long fixed_accuracy,
0057         unsigned long clk_fixed_flags)
0058 {
0059     struct clk_fixed_rate *fixed;
0060     struct clk_hw *hw;
0061     struct clk_init_data init = {};
0062     int ret = -EINVAL;
0063 
0064     /* allocate fixed-rate clock */
0065     fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
0066     if (!fixed)
0067         return ERR_PTR(-ENOMEM);
0068 
0069     init.name = name;
0070     init.ops = &clk_fixed_rate_ops;
0071     init.flags = flags;
0072     init.parent_names = parent_name ? &parent_name : NULL;
0073     init.parent_hws = parent_hw ? &parent_hw : NULL;
0074     init.parent_data = parent_data;
0075     if (parent_name || parent_hw || parent_data)
0076         init.num_parents = 1;
0077     else
0078         init.num_parents = 0;
0079 
0080     /* struct clk_fixed_rate assignments */
0081     fixed->flags = clk_fixed_flags;
0082     fixed->fixed_rate = fixed_rate;
0083     fixed->fixed_accuracy = fixed_accuracy;
0084     fixed->hw.init = &init;
0085 
0086     /* register the clock */
0087     hw = &fixed->hw;
0088     if (dev || !np)
0089         ret = clk_hw_register(dev, hw);
0090     else
0091         ret = of_clk_hw_register(np, hw);
0092     if (ret) {
0093         kfree(fixed);
0094         hw = ERR_PTR(ret);
0095     }
0096 
0097     return hw;
0098 }
0099 EXPORT_SYMBOL_GPL(__clk_hw_register_fixed_rate);
0100 
0101 struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
0102         const char *parent_name, unsigned long flags,
0103         unsigned long fixed_rate)
0104 {
0105     struct clk_hw *hw;
0106 
0107     hw = clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name,
0108                               flags, fixed_rate, 0);
0109     if (IS_ERR(hw))
0110         return ERR_CAST(hw);
0111     return hw->clk;
0112 }
0113 EXPORT_SYMBOL_GPL(clk_register_fixed_rate);
0114 
0115 void clk_unregister_fixed_rate(struct clk *clk)
0116 {
0117     struct clk_hw *hw;
0118 
0119     hw = __clk_get_hw(clk);
0120     if (!hw)
0121         return;
0122 
0123     clk_unregister(clk);
0124     kfree(to_clk_fixed_rate(hw));
0125 }
0126 EXPORT_SYMBOL_GPL(clk_unregister_fixed_rate);
0127 
0128 void clk_hw_unregister_fixed_rate(struct clk_hw *hw)
0129 {
0130     struct clk_fixed_rate *fixed;
0131 
0132     fixed = to_clk_fixed_rate(hw);
0133 
0134     clk_hw_unregister(hw);
0135     kfree(fixed);
0136 }
0137 EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate);
0138 
0139 #ifdef CONFIG_OF
0140 static struct clk_hw *_of_fixed_clk_setup(struct device_node *node)
0141 {
0142     struct clk_hw *hw;
0143     const char *clk_name = node->name;
0144     u32 rate;
0145     u32 accuracy = 0;
0146     int ret;
0147 
0148     if (of_property_read_u32(node, "clock-frequency", &rate))
0149         return ERR_PTR(-EIO);
0150 
0151     of_property_read_u32(node, "clock-accuracy", &accuracy);
0152 
0153     of_property_read_string(node, "clock-output-names", &clk_name);
0154 
0155     hw = clk_hw_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
0156                             0, rate, accuracy);
0157     if (IS_ERR(hw))
0158         return hw;
0159 
0160     ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
0161     if (ret) {
0162         clk_hw_unregister_fixed_rate(hw);
0163         return ERR_PTR(ret);
0164     }
0165 
0166     return hw;
0167 }
0168 
0169 /**
0170  * of_fixed_clk_setup() - Setup function for simple fixed rate clock
0171  * @node:   device node for the clock
0172  */
0173 void __init of_fixed_clk_setup(struct device_node *node)
0174 {
0175     _of_fixed_clk_setup(node);
0176 }
0177 CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
0178 
0179 static int of_fixed_clk_remove(struct platform_device *pdev)
0180 {
0181     struct clk_hw *hw = platform_get_drvdata(pdev);
0182 
0183     of_clk_del_provider(pdev->dev.of_node);
0184     clk_hw_unregister_fixed_rate(hw);
0185 
0186     return 0;
0187 }
0188 
0189 static int of_fixed_clk_probe(struct platform_device *pdev)
0190 {
0191     struct clk_hw *hw;
0192 
0193     /*
0194      * This function is not executed when of_fixed_clk_setup
0195      * succeeded.
0196      */
0197     hw = _of_fixed_clk_setup(pdev->dev.of_node);
0198     if (IS_ERR(hw))
0199         return PTR_ERR(hw);
0200 
0201     platform_set_drvdata(pdev, hw);
0202 
0203     return 0;
0204 }
0205 
0206 static const struct of_device_id of_fixed_clk_ids[] = {
0207     { .compatible = "fixed-clock" },
0208     { }
0209 };
0210 
0211 static struct platform_driver of_fixed_clk_driver = {
0212     .driver = {
0213         .name = "of_fixed_clk",
0214         .of_match_table = of_fixed_clk_ids,
0215     },
0216     .probe = of_fixed_clk_probe,
0217     .remove = of_fixed_clk_remove,
0218 };
0219 builtin_platform_driver(of_fixed_clk_driver);
0220 #endif