0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk-provider.h>
0011 #include <linux/clkdev.h>
0012 #include <linux/clk/at91_pmc.h>
0013 #include <linux/of.h>
0014 #include <linux/regmap.h>
0015 #include <linux/mfd/syscon.h>
0016
0017 #include "pmc.h"
0018
0019 #define H32MX_MAX_FREQ 90000000
0020
0021 struct clk_sama5d4_h32mx {
0022 struct clk_hw hw;
0023 struct regmap *regmap;
0024 };
0025
0026 #define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw)
0027
0028 static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
0029 unsigned long parent_rate)
0030 {
0031 struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
0032 unsigned int mckr;
0033
0034 regmap_read(h32mxclk->regmap, AT91_PMC_MCKR, &mckr);
0035 if (mckr & AT91_PMC_H32MXDIV)
0036 return parent_rate / 2;
0037
0038 if (parent_rate > H32MX_MAX_FREQ)
0039 pr_warn("H32MX clock is too fast\n");
0040 return parent_rate;
0041 }
0042
0043 static long clk_sama5d4_h32mx_round_rate(struct clk_hw *hw, unsigned long rate,
0044 unsigned long *parent_rate)
0045 {
0046 unsigned long div;
0047
0048 if (rate > *parent_rate)
0049 return *parent_rate;
0050 div = *parent_rate / 2;
0051 if (rate < div)
0052 return div;
0053
0054 if (rate - div < *parent_rate - rate)
0055 return div;
0056
0057 return *parent_rate;
0058 }
0059
0060 static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
0061 unsigned long parent_rate)
0062 {
0063 struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
0064 u32 mckr = 0;
0065
0066 if (parent_rate != rate && (parent_rate / 2) != rate)
0067 return -EINVAL;
0068
0069 if ((parent_rate / 2) == rate)
0070 mckr = AT91_PMC_H32MXDIV;
0071
0072 regmap_update_bits(h32mxclk->regmap, AT91_PMC_MCKR,
0073 AT91_PMC_H32MXDIV, mckr);
0074
0075 return 0;
0076 }
0077
0078 static const struct clk_ops h32mx_ops = {
0079 .recalc_rate = clk_sama5d4_h32mx_recalc_rate,
0080 .round_rate = clk_sama5d4_h32mx_round_rate,
0081 .set_rate = clk_sama5d4_h32mx_set_rate,
0082 };
0083
0084 struct clk_hw * __init
0085 at91_clk_register_h32mx(struct regmap *regmap, const char *name,
0086 const char *parent_name)
0087 {
0088 struct clk_sama5d4_h32mx *h32mxclk;
0089 struct clk_init_data init;
0090 int ret;
0091
0092 h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
0093 if (!h32mxclk)
0094 return ERR_PTR(-ENOMEM);
0095
0096 init.name = name;
0097 init.ops = &h32mx_ops;
0098 init.parent_names = parent_name ? &parent_name : NULL;
0099 init.num_parents = parent_name ? 1 : 0;
0100 init.flags = CLK_SET_RATE_GATE;
0101
0102 h32mxclk->hw.init = &init;
0103 h32mxclk->regmap = regmap;
0104
0105 ret = clk_hw_register(NULL, &h32mxclk->hw);
0106 if (ret) {
0107 kfree(h32mxclk);
0108 return ERR_PTR(ret);
0109 }
0110
0111 return &h32mxclk->hw;
0112 }