~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-imx/clk-fixup-div.c

Version: ~ [ linux-5.10-rc5 ] ~ [ linux-5.9.10 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.79 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.159 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.208 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.245 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.245 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2013 Freescale Semiconductor, Inc.
  3  *
  4  * The code contained herein is licensed under the GNU General Public
  5  * License. You may obtain a copy of the GNU General Public License
  6  * Version 2 or later at the following locations:
  7  *
  8  * http://www.opensource.org/licenses/gpl-license.html
  9  * http://www.gnu.org/copyleft/gpl.html
 10  */
 11 
 12 #include <linux/clk-provider.h>
 13 #include <linux/err.h>
 14 #include <linux/io.h>
 15 #include <linux/slab.h>
 16 #include "clk.h"
 17 
 18 #define to_clk_div(_hw) container_of(_hw, struct clk_divider, hw)
 19 #define div_mask(d)     ((1 << (d->width)) - 1)
 20 
 21 /**
 22  * struct clk_fixup_div - imx integer fixup divider clock
 23  * @divider: the parent class
 24  * @ops: pointer to clk_ops of parent class
 25  * @fixup: a hook to fixup the write value
 26  *
 27  * The imx fixup divider clock is a subclass of basic clk_divider
 28  * with an addtional fixup hook.
 29  */
 30 struct clk_fixup_div {
 31         struct clk_divider divider;
 32         const struct clk_ops *ops;
 33         void (*fixup)(u32 *val);
 34 };
 35 
 36 static inline struct clk_fixup_div *to_clk_fixup_div(struct clk_hw *hw)
 37 {
 38         struct clk_divider *divider = to_clk_div(hw);
 39 
 40         return container_of(divider, struct clk_fixup_div, divider);
 41 }
 42 
 43 static unsigned long clk_fixup_div_recalc_rate(struct clk_hw *hw,
 44                                          unsigned long parent_rate)
 45 {
 46         struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
 47 
 48         return fixup_div->ops->recalc_rate(&fixup_div->divider.hw, parent_rate);
 49 }
 50 
 51 static long clk_fixup_div_round_rate(struct clk_hw *hw, unsigned long rate,
 52                                unsigned long *prate)
 53 {
 54         struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
 55 
 56         return fixup_div->ops->round_rate(&fixup_div->divider.hw, rate, prate);
 57 }
 58 
 59 static int clk_fixup_div_set_rate(struct clk_hw *hw, unsigned long rate,
 60                             unsigned long parent_rate)
 61 {
 62         struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
 63         struct clk_divider *div = to_clk_div(hw);
 64         unsigned int divider, value;
 65         unsigned long flags = 0;
 66         u32 val;
 67 
 68         divider = parent_rate / rate;
 69 
 70         /* Zero based divider */
 71         value = divider - 1;
 72 
 73         if (value > div_mask(div))
 74                 value = div_mask(div);
 75 
 76         spin_lock_irqsave(div->lock, flags);
 77 
 78         val = readl(div->reg);
 79         val &= ~(div_mask(div) << div->shift);
 80         val |= value << div->shift;
 81         fixup_div->fixup(&val);
 82         writel(val, div->reg);
 83 
 84         spin_unlock_irqrestore(div->lock, flags);
 85 
 86         return 0;
 87 }
 88 
 89 static const struct clk_ops clk_fixup_div_ops = {
 90         .recalc_rate = clk_fixup_div_recalc_rate,
 91         .round_rate = clk_fixup_div_round_rate,
 92         .set_rate = clk_fixup_div_set_rate,
 93 };
 94 
 95 struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
 96                                   void __iomem *reg, u8 shift, u8 width,
 97                                   void (*fixup)(u32 *val))
 98 {
 99         struct clk_fixup_div *fixup_div;
100         struct clk *clk;
101         struct clk_init_data init;
102 
103         if (!fixup)
104                 return ERR_PTR(-EINVAL);
105 
106         fixup_div = kzalloc(sizeof(*fixup_div), GFP_KERNEL);
107         if (!fixup_div)
108                 return ERR_PTR(-ENOMEM);
109 
110         init.name = name;
111         init.ops = &clk_fixup_div_ops;
112         init.flags = CLK_SET_RATE_PARENT;
113         init.parent_names = parent ? &parent : NULL;
114         init.num_parents = parent ? 1 : 0;
115 
116         fixup_div->divider.reg = reg;
117         fixup_div->divider.shift = shift;
118         fixup_div->divider.width = width;
119         fixup_div->divider.lock = &imx_ccm_lock;
120         fixup_div->divider.hw.init = &init;
121         fixup_div->ops = &clk_divider_ops;
122         fixup_div->fixup = fixup;
123 
124         clk = clk_register(NULL, &fixup_div->divider.hw);
125         if (IS_ERR(clk))
126                 kfree(fixup_div);
127 
128         return clk;
129 }
130 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp