1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 2020-2022 MaxLinear, Inc. 4 * Copyright (C) 2020 Intel Corporation. 5 * Zhu Yixin <yzhu@maxlinear.com> 6 * Rahul Tanwar <rtanwar@maxlinear.com> 7 */ 8 9 #ifndef __CLK_CGU_H 10 #define __CLK_CGU_H 11 12 #include <linux/regmap.h> 13 14 struct lgm_clk_mux { 15 struct clk_hw hw; 16 struct regmap *membase; 17 unsigned int reg; 18 u8 shift; 19 u8 width; 20 unsigned long flags; 21 }; 22 23 struct lgm_clk_divider { 24 struct clk_hw hw; 25 struct regmap *membase; 26 unsigned int reg; 27 u8 shift; 28 u8 width; 29 u8 shift_gate; 30 u8 width_gate; 31 unsigned long flags; 32 const struct clk_div_table *table; 33 }; 34 35 struct lgm_clk_ddiv { 36 struct clk_hw hw; 37 struct regmap *membase; 38 unsigned int reg; 39 u8 shift0; 40 u8 width0; 41 u8 shift1; 42 u8 width1; 43 u8 shift2; 44 u8 width2; 45 u8 shift_gate; 46 u8 width_gate; 47 unsigned int mult; 48 unsigned int div; 49 unsigned long flags; 50 }; 51 52 struct lgm_clk_gate { 53 struct clk_hw hw; 54 struct regmap *membase; 55 unsigned int reg; 56 u8 shift; 57 unsigned long flags; 58 }; 59 60 enum lgm_clk_type { 61 CLK_TYPE_FIXED, 62 CLK_TYPE_MUX, 63 CLK_TYPE_DIVIDER, 64 CLK_TYPE_FIXED_FACTOR, 65 CLK_TYPE_GATE, 66 CLK_TYPE_NONE, 67 }; 68 69 /** 70 * struct lgm_clk_provider 71 * @membase: IO mem base address for CGU. 72 * @np: device node 73 * @dev: device 74 * @clk_data: array of hw clocks and clk number. 75 */ 76 struct lgm_clk_provider { 77 struct regmap *membase; 78 struct device_node *np; 79 struct device *dev; 80 struct clk_hw_onecell_data clk_data; 81 }; 82 83 enum pll_type { 84 TYPE_ROPLL, 85 TYPE_LJPLL, 86 TYPE_NONE, 87 }; 88 89 struct lgm_clk_pll { 90 struct clk_hw hw; 91 struct regmap *membase; 92 unsigned int reg; 93 unsigned long flags; 94 enum pll_type type; 95 }; 96 97 /** 98 * struct lgm_pll_clk_data 99 * @id: platform specific id of the clock. 100 * @name: name of this pll clock. 101 * @parent_data: parent clock data. 102 * @num_parents: number of parents. 103 * @flags: optional flags for basic clock. 104 * @type: platform type of pll. 105 * @reg: offset of the register. 106 */ 107 struct lgm_pll_clk_data { 108 unsigned int id; 109 const char *name; 110 const struct clk_parent_data *parent_data; 111 u8 num_parents; 112 unsigned long flags; 113 enum pll_type type; 114 int reg; 115 }; 116 117 #define LGM_PLL(_id, _name, _pdata, _flags, \ 118 _reg, _type) \ 119 { \ 120 .id = _id, \ 121 .name = _name, \ 122 .parent_data = _pdata, \ 123 .num_parents = ARRAY_SIZE(_pdata), \ 124 .flags = _flags, \ 125 .reg = _reg, \ 126 .type = _type, \ 127 } 128 129 struct lgm_clk_ddiv_data { 130 unsigned int id; 131 const char *name; 132 const struct clk_parent_data *parent_data; 133 u8 flags; 134 unsigned long div_flags; 135 unsigned int reg; 136 u8 shift0; 137 u8 width0; 138 u8 shift1; 139 u8 width1; 140 u8 shift_gate; 141 u8 width_gate; 142 u8 ex_shift; 143 u8 ex_width; 144 }; 145 146 #define LGM_DDIV(_id, _name, _pname, _flags, _reg, \ 147 _shft0, _wdth0, _shft1, _wdth1, \ 148 _shft_gate, _wdth_gate, _xshft, _df) \ 149 { \ 150 .id = _id, \ 151 .name = _name, \ 152 .parent_data = &(const struct clk_parent_data){ \ 153 .fw_name = _pname, \ 154 .name = _pname, \ 155 }, \ 156 .flags = _flags, \ 157 .reg = _reg, \ 158 .shift0 = _shft0, \ 159 .width0 = _wdth0, \ 160 .shift1 = _shft1, \ 161 .width1 = _wdth1, \ 162 .shift_gate = _shft_gate, \ 163 .width_gate = _wdth_gate, \ 164 .ex_shift = _xshft, \ 165 .ex_width = 1, \ 166 .div_flags = _df, \ 167 } 168 169 struct lgm_clk_branch { 170 unsigned int id; 171 enum lgm_clk_type type; 172 const char *name; 173 const struct clk_parent_data *parent_data; 174 u8 num_parents; 175 unsigned long flags; 176 unsigned int mux_off; 177 u8 mux_shift; 178 u8 mux_width; 179 unsigned long mux_flags; 180 unsigned int mux_val; 181 unsigned int div_off; 182 u8 div_shift; 183 u8 div_width; 184 u8 div_shift_gate; 185 u8 div_width_gate; 186 unsigned long div_flags; 187 unsigned int div_val; 188 const struct clk_div_table *div_table; 189 unsigned int gate_off; 190 u8 gate_shift; 191 unsigned long gate_flags; 192 unsigned int gate_val; 193 unsigned int mult; 194 unsigned int div; 195 }; 196 197 /* clock flags definition */ 198 #define CLOCK_FLAG_VAL_INIT BIT(16) 199 #define MUX_CLK_SW BIT(17) 200 #define GATE_CLK_HW BIT(18) 201 #define DIV_CLK_NO_MASK BIT(19) 202 203 #define LGM_MUX(_id, _name, _pdata, _f, _reg, \ 204 _shift, _width, _cf, _v) \ 205 { \ 206 .id = _id, \ 207 .type = CLK_TYPE_MUX, \ 208 .name = _name, \ 209 .parent_data = _pdata, \ 210 .num_parents = ARRAY_SIZE(_pdata), \ 211 .flags = _f, \ 212 .mux_off = _reg, \ 213 .mux_shift = _shift, \ 214 .mux_width = _width, \ 215 .mux_flags = _cf, \ 216 .mux_val = _v, \ 217 } 218 219 #define LGM_DIV(_id, _name, _pname, _f, _reg, _shift, _width, \ 220 _shift_gate, _width_gate, _cf, _v, _dtable) \ 221 { \ 222 .id = _id, \ 223 .type = CLK_TYPE_DIVIDER, \ 224 .name = _name, \ 225 .parent_data = &(const struct clk_parent_data){ \ 226 .fw_name = _pname, \ 227 .name = _pname, \ 228 }, \ 229 .num_parents = 1, \ 230 .flags = _f, \ 231 .div_off = _reg, \ 232 .div_shift = _shift, \ 233 .div_width = _width, \ 234 .div_shift_gate = _shift_gate, \ 235 .div_width_gate = _width_gate, \ 236 .div_flags = _cf, \ 237 .div_val = _v, \ 238 .div_table = _dtable, \ 239 } 240 241 #define LGM_GATE(_id, _name, _pname, _f, _reg, \ 242 _shift, _cf, _v) \ 243 { \ 244 .id = _id, \ 245 .type = CLK_TYPE_GATE, \ 246 .name = _name, \ 247 .parent_data = &(const struct clk_parent_data){ \ 248 .fw_name = _pname, \ 249 .name = _pname, \ 250 }, \ 251 .num_parents = !_pname ? 0 : 1, \ 252 .flags = _f, \ 253 .gate_off = _reg, \ 254 .gate_shift = _shift, \ 255 .gate_flags = _cf, \ 256 .gate_val = _v, \ 257 } 258 259 #define LGM_FIXED(_id, _name, _pname, _f, _reg, \ 260 _shift, _width, _cf, _freq, _v) \ 261 { \ 262 .id = _id, \ 263 .type = CLK_TYPE_FIXED, \ 264 .name = _name, \ 265 .parent_data = &(const struct clk_parent_data){ \ 266 .fw_name = _pname, \ 267 .name = _pname, \ 268 }, \ 269 .num_parents = !_pname ? 0 : 1, \ 270 .flags = _f, \ 271 .div_off = _reg, \ 272 .div_shift = _shift, \ 273 .div_width = _width, \ 274 .div_flags = _cf, \ 275 .div_val = _v, \ 276 .mux_flags = _freq, \ 277 } 278 279 #define LGM_FIXED_FACTOR(_id, _name, _pname, _f, _reg, \ 280 _shift, _width, _cf, _v, _m, _d) \ 281 { \ 282 .id = _id, \ 283 .type = CLK_TYPE_FIXED_FACTOR, \ 284 .name = _name, \ 285 .parent_data = &(const struct clk_parent_data){ \ 286 .fw_name = _pname, \ 287 .name = _pname, \ 288 }, \ 289 .num_parents = 1, \ 290 .flags = _f, \ 291 .div_off = _reg, \ 292 .div_shift = _shift, \ 293 .div_width = _width, \ 294 .div_flags = _cf, \ 295 .div_val = _v, \ 296 .mult = _m, \ 297 .div = _d, \ 298 } 299 300 static inline void lgm_set_clk_val(struct regmap *membase, u32 reg, 301 u8 shift, u8 width, u32 set_val) 302 { 303 u32 mask = (GENMASK(width - 1, 0) << shift); 304 305 regmap_update_bits(membase, reg, mask, set_val << shift); 306 } 307 308 static inline u32 lgm_get_clk_val(struct regmap *membase, u32 reg, 309 u8 shift, u8 width) 310 { 311 u32 mask = (GENMASK(width - 1, 0) << shift); 312 u32 val; 313 314 if (regmap_read(membase, reg, &val)) { 315 WARN_ONCE(1, "Failed to read clk reg: 0x%x\n", reg); 316 return 0; 317 } 318 319 val = (val & mask) >> shift; 320 321 return val; 322 } 323 324 325 326 int lgm_clk_register_branches(struct lgm_clk_provider *ctx, 327 const struct lgm_clk_branch *list, 328 unsigned int nr_clk); 329 int lgm_clk_register_plls(struct lgm_clk_provider *ctx, 330 const struct lgm_pll_clk_data *list, 331 unsigned int nr_clk); 332 int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx, 333 const struct lgm_clk_ddiv_data *list, 334 unsigned int nr_clk); 335 #endif /* __CLK_CGU_H */ 336