| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame^] | 1 | /* | 
|  | 2 | * Sysctrl clock implementation for ux500 platform. | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2013 ST-Ericsson SA | 
|  | 5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | 
|  | 6 | * | 
|  | 7 | * License terms: GNU General Public License (GPL) version 2 | 
|  | 8 | */ | 
|  | 9 |  | 
|  | 10 | #include <linux/clk-provider.h> | 
|  | 11 | #include <linux/mfd/abx500/ab8500-sysctrl.h> | 
|  | 12 | #include <linux/device.h> | 
|  | 13 | #include <linux/slab.h> | 
|  | 14 | #include <linux/delay.h> | 
|  | 15 | #include <linux/io.h> | 
|  | 16 | #include <linux/err.h> | 
|  | 17 | #include "clk.h" | 
|  | 18 |  | 
|  | 19 | #define SYSCTRL_MAX_NUM_PARENTS 4 | 
|  | 20 |  | 
|  | 21 | #define to_clk_sysctrl(_hw) container_of(_hw, struct clk_sysctrl, hw) | 
|  | 22 |  | 
|  | 23 | struct clk_sysctrl { | 
|  | 24 | struct clk_hw hw; | 
|  | 25 | struct device *dev; | 
|  | 26 | u8 parent_index; | 
|  | 27 | u16 reg_sel[SYSCTRL_MAX_NUM_PARENTS]; | 
|  | 28 | u8 reg_mask[SYSCTRL_MAX_NUM_PARENTS]; | 
|  | 29 | u8 reg_bits[SYSCTRL_MAX_NUM_PARENTS]; | 
|  | 30 | unsigned long rate; | 
|  | 31 | unsigned long enable_delay_us; | 
|  | 32 | }; | 
|  | 33 |  | 
|  | 34 | /* Sysctrl clock operations. */ | 
|  | 35 |  | 
|  | 36 | static int clk_sysctrl_prepare(struct clk_hw *hw) | 
|  | 37 | { | 
|  | 38 | int ret; | 
|  | 39 | struct clk_sysctrl *clk = to_clk_sysctrl(hw); | 
|  | 40 |  | 
|  | 41 | ret = ab8500_sysctrl_write(clk->reg_sel[0], clk->reg_mask[0], | 
|  | 42 | clk->reg_bits[0]); | 
|  | 43 |  | 
|  | 44 | if (!ret && clk->enable_delay_us) | 
|  | 45 | usleep_range(clk->enable_delay_us, clk->enable_delay_us); | 
|  | 46 |  | 
|  | 47 | return ret; | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | static void clk_sysctrl_unprepare(struct clk_hw *hw) | 
|  | 51 | { | 
|  | 52 | struct clk_sysctrl *clk = to_clk_sysctrl(hw); | 
|  | 53 | if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0])) | 
|  | 54 | dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n", | 
|  | 55 | __func__, clk_hw_get_name(hw)); | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | static unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw, | 
|  | 59 | unsigned long parent_rate) | 
|  | 60 | { | 
|  | 61 | struct clk_sysctrl *clk = to_clk_sysctrl(hw); | 
|  | 62 | return clk->rate; | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | static int clk_sysctrl_set_parent(struct clk_hw *hw, u8 index) | 
|  | 66 | { | 
|  | 67 | struct clk_sysctrl *clk = to_clk_sysctrl(hw); | 
|  | 68 | u8 old_index = clk->parent_index; | 
|  | 69 | int ret = 0; | 
|  | 70 |  | 
|  | 71 | if (clk->reg_sel[old_index]) { | 
|  | 72 | ret = ab8500_sysctrl_clear(clk->reg_sel[old_index], | 
|  | 73 | clk->reg_mask[old_index]); | 
|  | 74 | if (ret) | 
|  | 75 | return ret; | 
|  | 76 | } | 
|  | 77 |  | 
|  | 78 | if (clk->reg_sel[index]) { | 
|  | 79 | ret = ab8500_sysctrl_write(clk->reg_sel[index], | 
|  | 80 | clk->reg_mask[index], | 
|  | 81 | clk->reg_bits[index]); | 
|  | 82 | if (ret) { | 
|  | 83 | if (clk->reg_sel[old_index]) | 
|  | 84 | ab8500_sysctrl_write(clk->reg_sel[old_index], | 
|  | 85 | clk->reg_mask[old_index], | 
|  | 86 | clk->reg_bits[old_index]); | 
|  | 87 | return ret; | 
|  | 88 | } | 
|  | 89 | } | 
|  | 90 | clk->parent_index = index; | 
|  | 91 |  | 
|  | 92 | return ret; | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | static u8 clk_sysctrl_get_parent(struct clk_hw *hw) | 
|  | 96 | { | 
|  | 97 | struct clk_sysctrl *clk = to_clk_sysctrl(hw); | 
|  | 98 | return clk->parent_index; | 
|  | 99 | } | 
|  | 100 |  | 
|  | 101 | static const struct clk_ops clk_sysctrl_gate_ops = { | 
|  | 102 | .prepare = clk_sysctrl_prepare, | 
|  | 103 | .unprepare = clk_sysctrl_unprepare, | 
|  | 104 | }; | 
|  | 105 |  | 
|  | 106 | static const struct clk_ops clk_sysctrl_gate_fixed_rate_ops = { | 
|  | 107 | .prepare = clk_sysctrl_prepare, | 
|  | 108 | .unprepare = clk_sysctrl_unprepare, | 
|  | 109 | .recalc_rate = clk_sysctrl_recalc_rate, | 
|  | 110 | }; | 
|  | 111 |  | 
|  | 112 | static const struct clk_ops clk_sysctrl_set_parent_ops = { | 
|  | 113 | .set_parent = clk_sysctrl_set_parent, | 
|  | 114 | .get_parent = clk_sysctrl_get_parent, | 
|  | 115 | }; | 
|  | 116 |  | 
|  | 117 | static struct clk *clk_reg_sysctrl(struct device *dev, | 
|  | 118 | const char *name, | 
|  | 119 | const char **parent_names, | 
|  | 120 | u8 num_parents, | 
|  | 121 | u16 *reg_sel, | 
|  | 122 | u8 *reg_mask, | 
|  | 123 | u8 *reg_bits, | 
|  | 124 | unsigned long rate, | 
|  | 125 | unsigned long enable_delay_us, | 
|  | 126 | unsigned long flags, | 
|  | 127 | const struct clk_ops *clk_sysctrl_ops) | 
|  | 128 | { | 
|  | 129 | struct clk_sysctrl *clk; | 
|  | 130 | struct clk_init_data clk_sysctrl_init; | 
|  | 131 | struct clk *clk_reg; | 
|  | 132 | int i; | 
|  | 133 |  | 
|  | 134 | if (!dev) | 
|  | 135 | return ERR_PTR(-EINVAL); | 
|  | 136 |  | 
|  | 137 | if (!name || (num_parents > SYSCTRL_MAX_NUM_PARENTS)) { | 
|  | 138 | dev_err(dev, "clk_sysctrl: invalid arguments passed\n"); | 
|  | 139 | return ERR_PTR(-EINVAL); | 
|  | 140 | } | 
|  | 141 |  | 
|  | 142 | clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); | 
|  | 143 | if (!clk) | 
|  | 144 | return ERR_PTR(-ENOMEM); | 
|  | 145 |  | 
|  | 146 | /* set main clock registers */ | 
|  | 147 | clk->reg_sel[0] = reg_sel[0]; | 
|  | 148 | clk->reg_bits[0] = reg_bits[0]; | 
|  | 149 | clk->reg_mask[0] = reg_mask[0]; | 
|  | 150 |  | 
|  | 151 | /* handle clocks with more than one parent */ | 
|  | 152 | for (i = 1; i < num_parents; i++) { | 
|  | 153 | clk->reg_sel[i] = reg_sel[i]; | 
|  | 154 | clk->reg_bits[i] = reg_bits[i]; | 
|  | 155 | clk->reg_mask[i] = reg_mask[i]; | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | clk->parent_index = 0; | 
|  | 159 | clk->rate = rate; | 
|  | 160 | clk->enable_delay_us = enable_delay_us; | 
|  | 161 | clk->dev = dev; | 
|  | 162 |  | 
|  | 163 | clk_sysctrl_init.name = name; | 
|  | 164 | clk_sysctrl_init.ops = clk_sysctrl_ops; | 
|  | 165 | clk_sysctrl_init.flags = flags; | 
|  | 166 | clk_sysctrl_init.parent_names = parent_names; | 
|  | 167 | clk_sysctrl_init.num_parents = num_parents; | 
|  | 168 | clk->hw.init = &clk_sysctrl_init; | 
|  | 169 |  | 
|  | 170 | clk_reg = devm_clk_register(clk->dev, &clk->hw); | 
|  | 171 | if (IS_ERR(clk_reg)) | 
|  | 172 | dev_err(dev, "clk_sysctrl: clk_register failed\n"); | 
|  | 173 |  | 
|  | 174 | return clk_reg; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | struct clk *clk_reg_sysctrl_gate(struct device *dev, | 
|  | 178 | const char *name, | 
|  | 179 | const char *parent_name, | 
|  | 180 | u16 reg_sel, | 
|  | 181 | u8 reg_mask, | 
|  | 182 | u8 reg_bits, | 
|  | 183 | unsigned long enable_delay_us, | 
|  | 184 | unsigned long flags) | 
|  | 185 | { | 
|  | 186 | const char **parent_names = (parent_name ? &parent_name : NULL); | 
|  | 187 | u8 num_parents = (parent_name ? 1 : 0); | 
|  | 188 |  | 
|  | 189 | return clk_reg_sysctrl(dev, name, parent_names, num_parents, | 
|  | 190 | ®_sel, ®_mask, ®_bits, 0, enable_delay_us, | 
|  | 191 | flags, &clk_sysctrl_gate_ops); | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev, | 
|  | 195 | const char *name, | 
|  | 196 | const char *parent_name, | 
|  | 197 | u16 reg_sel, | 
|  | 198 | u8 reg_mask, | 
|  | 199 | u8 reg_bits, | 
|  | 200 | unsigned long rate, | 
|  | 201 | unsigned long enable_delay_us, | 
|  | 202 | unsigned long flags) | 
|  | 203 | { | 
|  | 204 | const char **parent_names = (parent_name ? &parent_name : NULL); | 
|  | 205 | u8 num_parents = (parent_name ? 1 : 0); | 
|  | 206 |  | 
|  | 207 | return clk_reg_sysctrl(dev, name, parent_names, num_parents, | 
|  | 208 | ®_sel, ®_mask, ®_bits, | 
|  | 209 | rate, enable_delay_us, flags, | 
|  | 210 | &clk_sysctrl_gate_fixed_rate_ops); | 
|  | 211 | } | 
|  | 212 |  | 
|  | 213 | struct clk *clk_reg_sysctrl_set_parent(struct device *dev, | 
|  | 214 | const char *name, | 
|  | 215 | const char **parent_names, | 
|  | 216 | u8 num_parents, | 
|  | 217 | u16 *reg_sel, | 
|  | 218 | u8 *reg_mask, | 
|  | 219 | u8 *reg_bits, | 
|  | 220 | unsigned long flags) | 
|  | 221 | { | 
|  | 222 | return clk_reg_sysctrl(dev, name, parent_names, num_parents, | 
|  | 223 | reg_sel, reg_mask, reg_bits, 0, 0, flags, | 
|  | 224 | &clk_sysctrl_set_parent_ops); | 
|  | 225 | } |