linux/drivers/clk/clk-fixed-factor.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * Standard functionality for the common clock API.
   9 */
  10#include <linux/module.h>
  11#include <linux/clk-provider.h>
  12#include <linux/slab.h>
  13#include <linux/err.h>
  14#include <linux/of.h>
  15
  16/*
  17 * DOC: basic fixed multiplier and divider clock that cannot gate
  18 *
  19 * Traits of this clock:
  20 * prepare - clk_prepare only ensures that parents are prepared
  21 * enable - clk_enable only ensures that parents are enabled
  22 * rate - rate is fixed.  clk->rate = parent->rate / div * mult
  23 * parent - fixed parent.  No clk_set_parent support
  24 */
  25
  26#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw)
  27
  28static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
  29                unsigned long parent_rate)
  30{
  31        struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
  32        unsigned long long int rate;
  33
  34        rate = (unsigned long long int)parent_rate * fix->mult;
  35        do_div(rate, fix->div);
  36        return (unsigned long)rate;
  37}
  38
  39static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
  40                                unsigned long *prate)
  41{
  42        struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
  43
  44        if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
  45                unsigned long best_parent;
  46
  47                best_parent = (rate / fix->mult) * fix->div;
  48                *prate = __clk_round_rate(__clk_get_parent(hw->clk),
  49                                best_parent);
  50        }
  51
  52        return (*prate / fix->div) * fix->mult;
  53}
  54
  55static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
  56                                unsigned long parent_rate)
  57{
  58        return 0;
  59}
  60
  61struct clk_ops clk_fixed_factor_ops = {
  62        .round_rate = clk_factor_round_rate,
  63        .set_rate = clk_factor_set_rate,
  64        .recalc_rate = clk_factor_recalc_rate,
  65};
  66EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
  67
  68struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
  69                const char *parent_name, unsigned long flags,
  70                unsigned int mult, unsigned int div)
  71{
  72        struct clk_fixed_factor *fix;
  73        struct clk_init_data init;
  74        struct clk *clk;
  75
  76        fix = kmalloc(sizeof(*fix), GFP_KERNEL);
  77        if (!fix) {
  78                pr_err("%s: could not allocate fixed factor clk\n", __func__);
  79                return ERR_PTR(-ENOMEM);
  80        }
  81
  82        /* struct clk_fixed_factor assignments */
  83        fix->mult = mult;
  84        fix->div = div;
  85        fix->hw.init = &init;
  86
  87        init.name = name;
  88        init.ops = &clk_fixed_factor_ops;
  89        init.flags = flags | CLK_IS_BASIC;
  90        init.parent_names = &parent_name;
  91        init.num_parents = 1;
  92
  93        clk = clk_register(dev, &fix->hw);
  94
  95        if (IS_ERR(clk))
  96                kfree(fix);
  97
  98        return clk;
  99}
 100EXPORT_SYMBOL_GPL(clk_register_fixed_factor);
 101
 102#ifdef CONFIG_OF
 103/**
 104 * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
 105 */
 106void __init of_fixed_factor_clk_setup(struct device_node *node)
 107{
 108        struct clk *clk;
 109        const char *clk_name = node->name;
 110        const char *parent_name;
 111        u32 div, mult;
 112
 113        if (of_property_read_u32(node, "clock-div", &div)) {
 114                pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
 115                        __func__, node->name);
 116                return;
 117        }
 118
 119        if (of_property_read_u32(node, "clock-mult", &mult)) {
 120                pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n",
 121                        __func__, node->name);
 122                return;
 123        }
 124
 125        of_property_read_string(node, "clock-output-names", &clk_name);
 126        parent_name = of_clk_get_parent_name(node, 0);
 127
 128        clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
 129                                        mult, div);
 130        if (!IS_ERR(clk))
 131                of_clk_add_provider(node, of_clk_src_simple_get, clk);
 132}
 133EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup);
 134CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
 135                of_fixed_factor_clk_setup);
 136#endif
 137