1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018 MediaTek Inc.
4 * Author: Owen Chen <owen.chen@mediatek.com>
8 #include <linux/of_address.h>
9 #include <linux/slab.h>
10 #include <linux/mfd/syscon.h>
15 static inline struct mtk_clk_mux
*to_mtk_clk_mux(struct clk_hw
*hw
)
17 return container_of(hw
, struct mtk_clk_mux
, hw
);
20 static int mtk_clk_mux_enable(struct clk_hw
*hw
)
22 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
23 u32 mask
= BIT(mux
->data
->gate_shift
);
25 return regmap_update_bits(mux
->regmap
, mux
->data
->mux_ofs
,
29 static void mtk_clk_mux_disable(struct clk_hw
*hw
)
31 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
32 u32 mask
= BIT(mux
->data
->gate_shift
);
34 regmap_update_bits(mux
->regmap
, mux
->data
->mux_ofs
, mask
, mask
);
37 static int mtk_clk_mux_enable_setclr(struct clk_hw
*hw
)
39 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
41 return regmap_write(mux
->regmap
, mux
->data
->clr_ofs
,
42 BIT(mux
->data
->gate_shift
));
45 static void mtk_clk_mux_disable_setclr(struct clk_hw
*hw
)
47 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
49 regmap_write(mux
->regmap
, mux
->data
->set_ofs
,
50 BIT(mux
->data
->gate_shift
));
53 static int mtk_clk_mux_is_enabled(struct clk_hw
*hw
)
55 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
58 regmap_read(mux
->regmap
, mux
->data
->mux_ofs
, &val
);
60 return (val
& BIT(mux
->data
->gate_shift
)) == 0;
63 static u8
mtk_clk_mux_get_parent(struct clk_hw
*hw
)
65 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
66 u32 mask
= GENMASK(mux
->data
->mux_width
- 1, 0);
69 regmap_read(mux
->regmap
, mux
->data
->mux_ofs
, &val
);
70 val
= (val
>> mux
->data
->mux_shift
) & mask
;
75 static int mtk_clk_mux_set_parent_lock(struct clk_hw
*hw
, u8 index
)
77 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
78 u32 mask
= GENMASK(mux
->data
->mux_width
- 1, 0);
79 unsigned long flags
= 0;
82 spin_lock_irqsave(mux
->lock
, flags
);
86 regmap_update_bits(mux
->regmap
, mux
->data
->mux_ofs
, mask
,
87 index
<< mux
->data
->mux_shift
);
90 spin_unlock_irqrestore(mux
->lock
, flags
);
97 static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw
*hw
, u8 index
)
99 struct mtk_clk_mux
*mux
= to_mtk_clk_mux(hw
);
100 u32 mask
= GENMASK(mux
->data
->mux_width
- 1, 0);
102 unsigned long flags
= 0;
105 spin_lock_irqsave(mux
->lock
, flags
);
107 __acquire(mux
->lock
);
109 regmap_read(mux
->regmap
, mux
->data
->mux_ofs
, &orig
);
110 val
= (orig
& ~(mask
<< mux
->data
->mux_shift
))
111 | (index
<< mux
->data
->mux_shift
);
114 regmap_write(mux
->regmap
, mux
->data
->clr_ofs
,
115 mask
<< mux
->data
->mux_shift
);
116 regmap_write(mux
->regmap
, mux
->data
->set_ofs
,
117 index
<< mux
->data
->mux_shift
);
119 if (mux
->data
->upd_shift
>= 0)
120 regmap_write(mux
->regmap
, mux
->data
->upd_ofs
,
121 BIT(mux
->data
->upd_shift
));
125 spin_unlock_irqrestore(mux
->lock
, flags
);
127 __release(mux
->lock
);
132 const struct clk_ops mtk_mux_ops
= {
133 .get_parent
= mtk_clk_mux_get_parent
,
134 .set_parent
= mtk_clk_mux_set_parent_lock
,
137 const struct clk_ops mtk_mux_clr_set_upd_ops
= {
138 .get_parent
= mtk_clk_mux_get_parent
,
139 .set_parent
= mtk_clk_mux_set_parent_setclr_lock
,
142 const struct clk_ops mtk_mux_gate_ops
= {
143 .enable
= mtk_clk_mux_enable
,
144 .disable
= mtk_clk_mux_disable
,
145 .is_enabled
= mtk_clk_mux_is_enabled
,
146 .get_parent
= mtk_clk_mux_get_parent
,
147 .set_parent
= mtk_clk_mux_set_parent_lock
,
150 const struct clk_ops mtk_mux_gate_clr_set_upd_ops
= {
151 .enable
= mtk_clk_mux_enable_setclr
,
152 .disable
= mtk_clk_mux_disable_setclr
,
153 .is_enabled
= mtk_clk_mux_is_enabled
,
154 .get_parent
= mtk_clk_mux_get_parent
,
155 .set_parent
= mtk_clk_mux_set_parent_setclr_lock
,
158 static struct clk
*mtk_clk_register_mux(const struct mtk_mux
*mux
,
159 struct regmap
*regmap
,
162 struct mtk_clk_mux
*clk_mux
;
163 struct clk_init_data init
= {};
166 clk_mux
= kzalloc(sizeof(*clk_mux
), GFP_KERNEL
);
168 return ERR_PTR(-ENOMEM
);
170 init
.name
= mux
->name
;
171 init
.flags
= mux
->flags
| CLK_SET_RATE_PARENT
;
172 init
.parent_names
= mux
->parent_names
;
173 init
.num_parents
= mux
->num_parents
;
176 clk_mux
->regmap
= regmap
;
178 clk_mux
->lock
= lock
;
179 clk_mux
->hw
.init
= &init
;
181 clk
= clk_register(NULL
, &clk_mux
->hw
);
190 int mtk_clk_register_muxes(const struct mtk_mux
*muxes
,
191 int num
, struct device_node
*node
,
193 struct clk_onecell_data
*clk_data
)
195 struct regmap
*regmap
;
199 regmap
= syscon_node_to_regmap(node
);
200 if (IS_ERR(regmap
)) {
201 pr_err("Cannot find regmap for %pOF: %ld\n", node
,
203 return PTR_ERR(regmap
);
206 for (i
= 0; i
< num
; i
++) {
207 const struct mtk_mux
*mux
= &muxes
[i
];
209 if (IS_ERR_OR_NULL(clk_data
->clks
[mux
->id
])) {
210 clk
= mtk_clk_register_mux(mux
, regmap
, lock
);
213 pr_err("Failed to register clk %s: %ld\n",
214 mux
->name
, PTR_ERR(clk
));
218 clk_data
->clks
[mux
->id
] = clk
;