1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2021 NXP
4  *
5  * Peng Fan <peng.fan@nxp.com>
6  */
7 
8 #include <linux/clk-provider.h>
9 #include <linux/errno.h>
10 #include <linux/export.h>
11 #include <linux/io.h>
12 #include <linux/slab.h>
13 
14 #include "clk.h"
15 
16 #define CCM_DIV_SHIFT	0
17 #define CCM_DIV_WIDTH	8
18 #define CCM_MUX_SHIFT	8
19 #define CCM_MUX_MASK	3
20 #define CCM_OFF_SHIFT	24
21 
22 #define AUTHEN_OFFSET	0x30
23 #define TZ_NS_SHIFT	9
24 #define TZ_NS_MASK	BIT(9)
25 
26 struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *parent_names,
27 					 int num_parents, void __iomem *reg,
28 					 unsigned long flags)
29 {
30 	struct clk_hw *hw = ERR_PTR(-ENOMEM), *mux_hw;
31 	struct clk_hw *div_hw, *gate_hw;
32 	struct clk_divider *div = NULL;
33 	struct clk_gate *gate = NULL;
34 	struct clk_mux *mux = NULL;
35 	bool clk_ro = false;
36 
37 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
38 	if (!mux)
39 		goto fail;
40 
41 	mux_hw = &mux->hw;
42 	mux->reg = reg;
43 	mux->shift = CCM_MUX_SHIFT;
44 	mux->mask = CCM_MUX_MASK;
45 	mux->lock = &imx_ccm_lock;
46 
47 	div = kzalloc(sizeof(*div), GFP_KERNEL);
48 	if (!div)
49 		goto fail;
50 
51 	div_hw = &div->hw;
52 	div->reg = reg;
53 	div->shift = CCM_DIV_SHIFT;
54 	div->width = CCM_DIV_WIDTH;
55 	div->lock = &imx_ccm_lock;
56 	div->flags = CLK_DIVIDER_ROUND_CLOSEST;
57 
58 	if (!(readl(reg + AUTHEN_OFFSET) & TZ_NS_MASK))
59 		clk_ro = true;
60 
61 	if (clk_ro) {
62 		hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
63 					       mux_hw, &clk_mux_ro_ops, div_hw,
64 					       &clk_divider_ro_ops, NULL, NULL, flags);
65 	} else {
66 		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
67 		if (!gate)
68 			goto fail;
69 
70 		gate_hw = &gate->hw;
71 		gate->reg = reg;
72 		gate->bit_idx = CCM_OFF_SHIFT;
73 		gate->lock = &imx_ccm_lock;
74 		gate->flags = CLK_GATE_SET_TO_DISABLE;
75 
76 		hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
77 					       mux_hw, &clk_mux_ops, div_hw,
78 					       &clk_divider_ops, gate_hw,
79 					       &clk_gate_ops, flags | CLK_SET_RATE_NO_REPARENT);
80 	}
81 
82 	if (IS_ERR(hw))
83 		goto fail;
84 
85 	return hw;
86 
87 fail:
88 	kfree(gate);
89 	kfree(div);
90 	kfree(mux);
91 	return ERR_CAST(hw);
92 }
93 EXPORT_SYMBOL_GPL(imx93_clk_composite_flags);
94