336 lines · c
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_H10#define __CLK_CGU_H11 12#include <linux/regmap.h>13 14struct 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 23struct 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 35struct 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 52struct 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 60enum 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_provider71 * @membase: IO mem base address for CGU.72 * @np: device node73 * @dev: device74 * @clk_data: array of hw clocks and clk number.75 */76struct 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 83enum pll_type {84 TYPE_ROPLL,85 TYPE_LJPLL,86 TYPE_NONE,87};88 89struct 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_data99 * @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 */107struct 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 129struct 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 169struct 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 300static 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 308static 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 326int lgm_clk_register_branches(struct lgm_clk_provider *ctx,327 const struct lgm_clk_branch *list,328 unsigned int nr_clk);329int lgm_clk_register_plls(struct lgm_clk_provider *ctx,330 const struct lgm_pll_clk_data *list,331 unsigned int nr_clk);332int 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