linux/drivers/clk/clk-fixed-factor.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
   4 */
   5#include <linux/module.h>
   6#include <linux/clk-provider.h>
   7#include <linux/slab.h>
   8#include <linux/err.h>
   9#include <linux/of.h>
  10#include <linux/platform_device.h>
  11
  12/*
  13 * DOC: basic fixed multiplier and divider clock that cannot gate
  14 *
  15 * Traits of this clock:
  16 * prepare - clk_prepare only ensures that parents are prepared
  17 * enable - clk_enable only ensures that parents are enabled
  18 * rate - rate is fixed.  clk->rate = parent->rate / div * mult
  19 * parent - fixed parent.  No clk_set_parent support
  20 */
  21
  22static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
  23                unsigned long parent_rate)
  24{
  25        struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
  26        unsigned long long int rate;
  27
  28        rate = (unsigned long long int)parent_rate * fix->mult;
  29        do_div(rate, fix->div);
  30        return (unsigned long)rate;
  31}
  32
  33static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
  34                                unsigned long *prate)
  35{
  36        struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
  37
  38        if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
  39                unsigned long best_parent;
  40
  41                best_parent = (rate / fix->mult) * fix->div;
  42                *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
  43        }
  44
  45        return (*prate / fix->div) * fix->mult;
  46}
  47
  48static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
  49                                unsigned long parent_rate)
  50{
  51        /*
  52         * We must report success but we can do so unconditionally because
  53         * clk_factor_round_rate returns values that ensure this call is a
  54         * nop.
  55         */
  56
  57        return 0;
  58}
  59
  60const struct clk_ops clk_fixed_factor_ops = {
  61        .round_rate = clk_factor_round_rate,
  62        .set_rate = clk_factor_set_rate,
  63        .recalc_rate = clk_factor_recalc_rate,
  64};
  65EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
  66
  67static void devm_clk_hw_register_fixed_factor_release(struct device *dev, void *res)
  68{
  69        struct clk_fixed_factor *fix = res;
  70
  71        /*
  72         * We can not use clk_hw_unregister_fixed_factor, since it will kfree()
  73         * the hw, resulting in double free. Just unregister the hw and let
  74         * devres code kfree() it.
  75         */
  76        clk_hw_unregister(&fix->hw);
  77}
  78
  79static struct clk_hw *
  80__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
  81                const char *name, const char *parent_name, int index,
  82                unsigned long flags, unsigned int mult, unsigned int div,
  83                bool devm)
  84{
  85        struct clk_fixed_factor *fix;
  86        struct clk_init_data init = { };
  87        struct clk_parent_data pdata = { .index = index };
  88        struct clk_hw *hw;
  89        int ret;
  90
  91        /* You can't use devm without a dev */
  92        if (devm && !dev)
  93                return ERR_PTR(-EINVAL);
  94
  95        if (devm)
  96                fix = devres_alloc(devm_clk_hw_register_fixed_factor_release,
  97                                sizeof(*fix), GFP_KERNEL);
  98        else
  99                fix = kmalloc(sizeof(*fix), GFP_KERNEL);
 100        if (!fix)
 101                return ERR_PTR(-ENOMEM);
 102
 103        /* struct clk_fixed_factor assignments */
 104        fix->mult = mult;
 105        fix->div = div;
 106        fix->hw.init = &init;
 107
 108        init.name = name;
 109        init.ops = &clk_fixed_factor_ops;
 110        init.flags = flags;
 111        if (parent_name)
 112                init.parent_names = &parent_name;
 113        else
 114                init.parent_data = &pdata;
 115        init.num_parents = 1;
 116
 117        hw = &fix->hw;
 118        if (dev)
 119                ret = clk_hw_register(dev, hw);
 120        else
 121                ret = of_clk_hw_register(np, hw);
 122        if (ret) {
 123                if (devm)
 124                        devres_free(fix);
 125                else
 126                        kfree(fix);
 127                hw = ERR_PTR(ret);
 128        } else if (devm)
 129                devres_add(dev, fix);
 130
 131        return hw;
 132}
 133
 134/**
 135 * devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with
 136 * parent from DT index
 137 * @dev: device that is registering this clock
 138 * @name: name of this clock
 139 * @index: index of phandle in @dev 'clocks' property
 140 * @flags: fixed factor flags
 141 * @mult: multiplier
 142 * @div: divider
 143 *
 144 * Return: Pointer to fixed factor clk_hw structure that was registered or
 145 * an error pointer.
 146 */
 147struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
 148                const char *name, unsigned int index, unsigned long flags,
 149                unsigned int mult, unsigned int div)
 150{
 151        return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, index,
 152                                              flags, mult, div, true);
 153}
 154EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index);
 155
 156struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
 157                const char *name, const char *parent_name, unsigned long flags,
 158                unsigned int mult, unsigned int div)
 159{
 160        return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, -1,
 161                                              flags, mult, div, false);
 162}
 163EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
 164
 165struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
 166                const char *parent_name, unsigned long flags,
 167                unsigned int mult, unsigned int div)
 168{
 169        struct clk_hw *hw;
 170
 171        hw = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult,
 172                                          div);
 173        if (IS_ERR(hw))
 174                return ERR_CAST(hw);
 175        return hw->clk;
 176}
 177EXPORT_SYMBOL_GPL(clk_register_fixed_factor);
 178
 179void clk_unregister_fixed_factor(struct clk *clk)
 180{
 181        struct clk_hw *hw;
 182
 183        hw = __clk_get_hw(clk);
 184        if (!hw)
 185                return;
 186
 187        clk_unregister(clk);
 188        kfree(to_clk_fixed_factor(hw));
 189}
 190EXPORT_SYMBOL_GPL(clk_unregister_fixed_factor);
 191
 192void clk_hw_unregister_fixed_factor(struct clk_hw *hw)
 193{
 194        struct clk_fixed_factor *fix;
 195
 196        fix = to_clk_fixed_factor(hw);
 197
 198        clk_hw_unregister(hw);
 199        kfree(fix);
 200}
 201EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor);
 202
 203struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
 204                const char *name, const char *parent_name, unsigned long flags,
 205                unsigned int mult, unsigned int div)
 206{
 207        return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, -1,
 208                        flags, mult, div, true);
 209}
 210EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor);
 211
 212#ifdef CONFIG_OF
 213static const struct of_device_id set_rate_parent_matches[] = {
 214        { .compatible = "allwinner,sun4i-a10-pll3-2x-clk" },
 215        { /* Sentinel */ },
 216};
 217
 218static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node)
 219{
 220        struct clk_hw *hw;
 221        const char *clk_name = node->name;
 222        unsigned long flags = 0;
 223        u32 div, mult;
 224        int ret;
 225
 226        if (of_property_read_u32(node, "clock-div", &div)) {
 227                pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n",
 228                        __func__, node);
 229                return ERR_PTR(-EIO);
 230        }
 231
 232        if (of_property_read_u32(node, "clock-mult", &mult)) {
 233                pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n",
 234                        __func__, node);
 235                return ERR_PTR(-EIO);
 236        }
 237
 238        of_property_read_string(node, "clock-output-names", &clk_name);
 239
 240        if (of_match_node(set_rate_parent_matches, node))
 241                flags |= CLK_SET_RATE_PARENT;
 242
 243        hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, 0,
 244                                            flags, mult, div, false);
 245        if (IS_ERR(hw)) {
 246                /*
 247                 * Clear OF_POPULATED flag so that clock registration can be
 248                 * attempted again from probe function.
 249                 */
 250                of_node_clear_flag(node, OF_POPULATED);
 251                return ERR_CAST(hw);
 252        }
 253
 254        ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
 255        if (ret) {
 256                clk_hw_unregister_fixed_factor(hw);
 257                return ERR_PTR(ret);
 258        }
 259
 260        return hw;
 261}
 262
 263/**
 264 * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
 265 * @node:       device node for the clock
 266 */
 267void __init of_fixed_factor_clk_setup(struct device_node *node)
 268{
 269        _of_fixed_factor_clk_setup(node);
 270}
 271CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
 272                of_fixed_factor_clk_setup);
 273
 274static int of_fixed_factor_clk_remove(struct platform_device *pdev)
 275{
 276        struct clk_hw *clk = platform_get_drvdata(pdev);
 277
 278        of_clk_del_provider(pdev->dev.of_node);
 279        clk_hw_unregister_fixed_factor(clk);
 280
 281        return 0;
 282}
 283
 284static int of_fixed_factor_clk_probe(struct platform_device *pdev)
 285{
 286        struct clk_hw *clk;
 287
 288        /*
 289         * This function is not executed when of_fixed_factor_clk_setup
 290         * succeeded.
 291         */
 292        clk = _of_fixed_factor_clk_setup(pdev->dev.of_node);
 293        if (IS_ERR(clk))
 294                return PTR_ERR(clk);
 295
 296        platform_set_drvdata(pdev, clk);
 297
 298        return 0;
 299}
 300
 301static const struct of_device_id of_fixed_factor_clk_ids[] = {
 302        { .compatible = "fixed-factor-clock" },
 303        { }
 304};
 305MODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids);
 306
 307static struct platform_driver of_fixed_factor_clk_driver = {
 308        .driver = {
 309                .name = "of_fixed_factor_clk",
 310                .of_match_table = of_fixed_factor_clk_ids,
 311        },
 312        .probe = of_fixed_factor_clk_probe,
 313        .remove = of_fixed_factor_clk_remove,
 314};
 315builtin_platform_driver(of_fixed_factor_clk_driver);
 316#endif
 317