0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/clk-provider.h>
0012 #include <linux/slab.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/clk/ti.h>
0016
0017 #include "clock.h"
0018
0019 #undef pr_fmt
0020 #define pr_fmt(fmt) "%s: " fmt, __func__
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 int omap2_clkops_enable_clkdm(struct clk_hw *hw)
0035 {
0036 struct clk_hw_omap *clk;
0037 int ret = 0;
0038
0039 clk = to_clk_hw_omap(hw);
0040
0041 if (unlikely(!clk->clkdm)) {
0042 pr_err("%s: %s: no clkdm set ?!\n", __func__,
0043 clk_hw_get_name(hw));
0044 return -EINVAL;
0045 }
0046
0047 if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
0048 pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
0049 __func__, clk_hw_get_name(hw));
0050 return 0;
0051 }
0052
0053 ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
0054 WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
0055 __func__, clk_hw_get_name(hw), clk->clkdm_name, ret);
0056
0057 return ret;
0058 }
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 void omap2_clkops_disable_clkdm(struct clk_hw *hw)
0070 {
0071 struct clk_hw_omap *clk;
0072
0073 clk = to_clk_hw_omap(hw);
0074
0075 if (unlikely(!clk->clkdm)) {
0076 pr_err("%s: %s: no clkdm set ?!\n", __func__,
0077 clk_hw_get_name(hw));
0078 return;
0079 }
0080
0081 if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
0082 pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
0083 __func__, clk_hw_get_name(hw));
0084 return;
0085 }
0086
0087 ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
0088 }
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 int omap2_init_clk_clkdm(struct clk_hw *hw)
0099 {
0100 struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0101 struct clockdomain *clkdm;
0102 const char *clk_name;
0103
0104 if (!clk->clkdm_name)
0105 return 0;
0106
0107 clk_name = __clk_get_name(hw->clk);
0108
0109 clkdm = ti_clk_ll_ops->clkdm_lookup(clk->clkdm_name);
0110 if (clkdm) {
0111 pr_debug("clock: associated clk %s to clkdm %s\n",
0112 clk_name, clk->clkdm_name);
0113 clk->clkdm = clkdm;
0114 } else {
0115 pr_debug("clock: could not associate clk %s to clkdm %s\n",
0116 clk_name, clk->clkdm_name);
0117 }
0118
0119 return 0;
0120 }
0121
0122 static void __init of_ti_clockdomain_setup(struct device_node *node)
0123 {
0124 struct clk *clk;
0125 struct clk_hw *clk_hw;
0126 const char *clkdm_name = ti_dt_clk_name(node);
0127 int i;
0128 unsigned int num_clks;
0129
0130 num_clks = of_clk_get_parent_count(node);
0131
0132 for (i = 0; i < num_clks; i++) {
0133 clk = of_clk_get(node, i);
0134 if (IS_ERR(clk)) {
0135 pr_err("%s: Failed get %pOF' clock nr %d (%ld)\n",
0136 __func__, node, i, PTR_ERR(clk));
0137 continue;
0138 }
0139 clk_hw = __clk_get_hw(clk);
0140 if (!omap2_clk_is_hw_omap(clk_hw)) {
0141 pr_warn("can't setup clkdm for basic clk %s\n",
0142 __clk_get_name(clk));
0143 clk_put(clk);
0144 continue;
0145 }
0146 to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name;
0147 omap2_init_clk_clkdm(clk_hw);
0148 clk_put(clk);
0149 }
0150 }
0151
0152 static const struct of_device_id ti_clkdm_match_table[] __initconst = {
0153 { .compatible = "ti,clockdomain" },
0154 { }
0155 };
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166 void __init ti_dt_clockdomains_setup(void)
0167 {
0168 struct device_node *np;
0169 for_each_matching_node(np, ti_clkdm_match_table) {
0170 of_ti_clockdomain_setup(np);
0171 }
0172 }