Merge tag 'folio-5.18d' of git://git.infradead.org/users/willy/pagecache
[linux-2.6-microblaze.git] / drivers / clk / imx / clk-composite-93.c
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);