Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: clk: st: Handle clk synchronous mode for video clocks

This patch configures the semi-synchronous mode of the video clocks
of clkgenD2.

Signed-off-by: Olivier Bideau <olivier.bideau@st.com>
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
Acked-by: Peter Griffin <peter.griffin@linaro.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Gabriel Fernandez and committed by
Stephen Boyd
cb80ec76 26bd0a57

+37 -2
+2
Documentation/devicetree/bindings/clock/st/st,flexgen.txt
··· 62 62 "st,flexgen" 63 63 "st,flexgen-audio", "st,flexgen" (enable clock propagation on parent for 64 64 audio use case) 65 + "st,flexgen-video", "st,flexgen" (enable clock propagation on parent 66 + and activate synchronous mode) 65 67 66 68 - #clock-cells : from common clock binding; shall be set to 1 (multiple clock 67 69 outputs).
+35 -2
drivers/clk/st/clk-flexgen.c
··· 17 17 18 18 struct clkgen_data { 19 19 unsigned long flags; 20 + bool mode; 20 21 }; 21 22 22 23 struct flexgen { ··· 33 32 struct clk_gate fgate; 34 33 /* Final divisor */ 35 34 struct clk_divider fdiv; 35 + /* Asynchronous mode control */ 36 + struct clk_gate sync; 37 + /* hw control flags */ 38 + bool control_mode; 36 39 }; 37 40 38 41 #define to_flexgen(_hw) container_of(_hw, struct flexgen, hw) 42 + #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) 39 43 40 44 static int flexgen_enable(struct clk_hw *hw) 41 45 { ··· 149 143 struct flexgen *flexgen = to_flexgen(hw); 150 144 struct clk_hw *pdiv_hw = &flexgen->pdiv.hw; 151 145 struct clk_hw *fdiv_hw = &flexgen->fdiv.hw; 146 + struct clk_hw *sync_hw = &flexgen->sync.hw; 147 + struct clk_gate *config = to_clk_gate(sync_hw); 152 148 unsigned long div = 0; 153 149 int ret = 0; 150 + u32 reg; 154 151 155 152 __clk_hw_set_clk(pdiv_hw, hw); 156 153 __clk_hw_set_clk(fdiv_hw, hw); 154 + 155 + if (flexgen->control_mode) { 156 + reg = readl(config->reg); 157 + reg &= ~BIT(config->bit_idx); 158 + writel(reg, config->reg); 159 + } 157 160 158 161 div = clk_best_div(parent_rate, rate); 159 162 ··· 197 182 static struct clk *clk_register_flexgen(const char *name, 198 183 const char **parent_names, u8 num_parents, 199 184 void __iomem *reg, spinlock_t *lock, u32 idx, 200 - unsigned long flexgen_flags) { 185 + unsigned long flexgen_flags, bool mode) { 201 186 struct flexgen *fgxbar; 202 187 struct clk *clk; 203 188 struct clk_init_data init; ··· 246 231 fgxbar->fdiv.reg = fdiv_reg; 247 232 fgxbar->fdiv.width = 6; 248 233 234 + /* Final divider sync config */ 235 + fgxbar->sync.lock = lock; 236 + fgxbar->sync.reg = fdiv_reg; 237 + fgxbar->sync.bit_idx = 7; 238 + 239 + fgxbar->control_mode = mode; 240 + 249 241 fgxbar->hw.init = &init; 250 242 251 243 clk = clk_register(NULL, &fgxbar->hw); ··· 289 267 .flags = CLK_SET_RATE_PARENT, 290 268 }; 291 269 270 + static const struct clkgen_data clkgen_video = { 271 + .flags = CLK_SET_RATE_PARENT, 272 + .mode = 1, 273 + }; 274 + 292 275 static const struct of_device_id flexgen_of_match[] = { 293 276 { 294 277 .compatible = "st,flexgen-audio", 295 278 .data = &clkgen_audio, 279 + }, 280 + { 281 + .compatible = "st,flexgen-video", 282 + .data = &clkgen_video, 296 283 }, 297 284 {} 298 285 }; ··· 318 287 struct clkgen_data *data = NULL; 319 288 unsigned long flex_flags = 0; 320 289 int ret; 290 + bool clk_mode = 0; 321 291 322 292 pnode = of_get_parent(np); 323 293 if (!pnode) ··· 336 304 if (match) { 337 305 data = (struct clkgen_data *)match->data; 338 306 flex_flags = data->flags; 307 + clk_mode = data->mode; 339 308 } 340 309 341 310 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); ··· 380 347 continue; 381 348 382 349 clk = clk_register_flexgen(clk_name, parents, num_parents, 383 - reg, rlock, i, flex_flags); 350 + reg, rlock, i, flex_flags, clk_mode); 384 351 385 352 if (IS_ERR(clk)) 386 353 goto err;