0001
0002
0003
0004
0005
0006
0007 #include <linux/bits.h>
0008 #include <linux/clk.h>
0009 #include <linux/clk-provider.h>
0010 #include <linux/io.h>
0011 #include <linux/slab.h>
0012 #include <linux/jiffies.h>
0013 #include <linux/err.h>
0014 #include "clk.h"
0015
0016 static int clk_busy_wait(void __iomem *reg, u8 shift)
0017 {
0018 unsigned long timeout = jiffies + msecs_to_jiffies(10);
0019
0020 while (readl_relaxed(reg) & (1 << shift))
0021 if (time_after(jiffies, timeout))
0022 return -ETIMEDOUT;
0023
0024 return 0;
0025 }
0026
0027 struct clk_busy_divider {
0028 struct clk_divider div;
0029 const struct clk_ops *div_ops;
0030 void __iomem *reg;
0031 u8 shift;
0032 };
0033
0034 static inline struct clk_busy_divider *to_clk_busy_divider(struct clk_hw *hw)
0035 {
0036 struct clk_divider *div = to_clk_divider(hw);
0037
0038 return container_of(div, struct clk_busy_divider, div);
0039 }
0040
0041 static unsigned long clk_busy_divider_recalc_rate(struct clk_hw *hw,
0042 unsigned long parent_rate)
0043 {
0044 struct clk_busy_divider *busy = to_clk_busy_divider(hw);
0045
0046 return busy->div_ops->recalc_rate(&busy->div.hw, parent_rate);
0047 }
0048
0049 static long clk_busy_divider_round_rate(struct clk_hw *hw, unsigned long rate,
0050 unsigned long *prate)
0051 {
0052 struct clk_busy_divider *busy = to_clk_busy_divider(hw);
0053
0054 return busy->div_ops->round_rate(&busy->div.hw, rate, prate);
0055 }
0056
0057 static int clk_busy_divider_set_rate(struct clk_hw *hw, unsigned long rate,
0058 unsigned long parent_rate)
0059 {
0060 struct clk_busy_divider *busy = to_clk_busy_divider(hw);
0061 int ret;
0062
0063 ret = busy->div_ops->set_rate(&busy->div.hw, rate, parent_rate);
0064 if (!ret)
0065 ret = clk_busy_wait(busy->reg, busy->shift);
0066
0067 return ret;
0068 }
0069
0070 static const struct clk_ops clk_busy_divider_ops = {
0071 .recalc_rate = clk_busy_divider_recalc_rate,
0072 .round_rate = clk_busy_divider_round_rate,
0073 .set_rate = clk_busy_divider_set_rate,
0074 };
0075
0076 struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name,
0077 void __iomem *reg, u8 shift, u8 width,
0078 void __iomem *busy_reg, u8 busy_shift)
0079 {
0080 struct clk_busy_divider *busy;
0081 struct clk_hw *hw;
0082 struct clk_init_data init;
0083 int ret;
0084
0085 busy = kzalloc(sizeof(*busy), GFP_KERNEL);
0086 if (!busy)
0087 return ERR_PTR(-ENOMEM);
0088
0089 busy->reg = busy_reg;
0090 busy->shift = busy_shift;
0091
0092 busy->div.reg = reg;
0093 busy->div.shift = shift;
0094 busy->div.width = width;
0095 busy->div.lock = &imx_ccm_lock;
0096 busy->div_ops = &clk_divider_ops;
0097
0098 init.name = name;
0099 init.ops = &clk_busy_divider_ops;
0100 init.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL;
0101 init.parent_names = &parent_name;
0102 init.num_parents = 1;
0103
0104 busy->div.hw.init = &init;
0105
0106 hw = &busy->div.hw;
0107
0108 ret = clk_hw_register(NULL, hw);
0109 if (ret) {
0110 kfree(busy);
0111 return ERR_PTR(ret);
0112 }
0113
0114 return hw;
0115 }
0116
0117 struct clk_busy_mux {
0118 struct clk_mux mux;
0119 const struct clk_ops *mux_ops;
0120 void __iomem *reg;
0121 u8 shift;
0122 };
0123
0124 static inline struct clk_busy_mux *to_clk_busy_mux(struct clk_hw *hw)
0125 {
0126 struct clk_mux *mux = to_clk_mux(hw);
0127
0128 return container_of(mux, struct clk_busy_mux, mux);
0129 }
0130
0131 static u8 clk_busy_mux_get_parent(struct clk_hw *hw)
0132 {
0133 struct clk_busy_mux *busy = to_clk_busy_mux(hw);
0134
0135 return busy->mux_ops->get_parent(&busy->mux.hw);
0136 }
0137
0138 static int clk_busy_mux_set_parent(struct clk_hw *hw, u8 index)
0139 {
0140 struct clk_busy_mux *busy = to_clk_busy_mux(hw);
0141 int ret;
0142
0143 ret = busy->mux_ops->set_parent(&busy->mux.hw, index);
0144 if (!ret)
0145 ret = clk_busy_wait(busy->reg, busy->shift);
0146
0147 return ret;
0148 }
0149
0150 static const struct clk_ops clk_busy_mux_ops = {
0151 .get_parent = clk_busy_mux_get_parent,
0152 .set_parent = clk_busy_mux_set_parent,
0153 };
0154
0155 struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift,
0156 u8 width, void __iomem *busy_reg, u8 busy_shift,
0157 const char * const *parent_names, int num_parents)
0158 {
0159 struct clk_busy_mux *busy;
0160 struct clk_hw *hw;
0161 struct clk_init_data init;
0162 int ret;
0163
0164 busy = kzalloc(sizeof(*busy), GFP_KERNEL);
0165 if (!busy)
0166 return ERR_PTR(-ENOMEM);
0167
0168 busy->reg = busy_reg;
0169 busy->shift = busy_shift;
0170
0171 busy->mux.reg = reg;
0172 busy->mux.shift = shift;
0173 busy->mux.mask = BIT(width) - 1;
0174 busy->mux.lock = &imx_ccm_lock;
0175 busy->mux_ops = &clk_mux_ops;
0176
0177 init.name = name;
0178 init.ops = &clk_busy_mux_ops;
0179 init.flags = CLK_IS_CRITICAL;
0180 init.parent_names = parent_names;
0181 init.num_parents = num_parents;
0182
0183 busy->mux.hw.init = &init;
0184
0185 hw = &busy->mux.hw;
0186
0187 ret = clk_hw_register(NULL, hw);
0188 if (ret) {
0189 kfree(busy);
0190 return ERR_PTR(ret);
0191 }
0192
0193 return hw;
0194 }