1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2015 Linaro Ltd.
4 * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
7 #include <linux/clk-provider.h>
8 #include <linux/container_of.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/module.h>
12 #include <linux/regmap.h>
13 #include <linux/slab.h>
16 #include "clk-cpumux.h"
18 struct mtk_clk_cpumux
{
20 struct regmap
*regmap
;
26 static inline struct mtk_clk_cpumux
*to_mtk_clk_cpumux(struct clk_hw
*_hw
)
28 return container_of(_hw
, struct mtk_clk_cpumux
, hw
);
31 static u8
clk_cpumux_get_parent(struct clk_hw
*hw
)
33 struct mtk_clk_cpumux
*mux
= to_mtk_clk_cpumux(hw
);
36 regmap_read(mux
->regmap
, mux
->reg
, &val
);
44 static int clk_cpumux_set_parent(struct clk_hw
*hw
, u8 index
)
46 struct mtk_clk_cpumux
*mux
= to_mtk_clk_cpumux(hw
);
49 val
= index
<< mux
->shift
;
50 mask
= mux
->mask
<< mux
->shift
;
52 return regmap_update_bits(mux
->regmap
, mux
->reg
, mask
, val
);
55 static const struct clk_ops clk_cpumux_ops
= {
56 .determine_rate
= clk_hw_determine_rate_no_reparent
,
57 .get_parent
= clk_cpumux_get_parent
,
58 .set_parent
= clk_cpumux_set_parent
,
61 static struct clk_hw
*
62 mtk_clk_register_cpumux(struct device
*dev
, const struct mtk_composite
*mux
,
63 struct regmap
*regmap
)
65 struct mtk_clk_cpumux
*cpumux
;
67 struct clk_init_data init
;
69 cpumux
= kzalloc(sizeof(*cpumux
), GFP_KERNEL
);
71 return ERR_PTR(-ENOMEM
);
73 init
.name
= mux
->name
;
74 init
.ops
= &clk_cpumux_ops
;
75 init
.parent_names
= mux
->parent_names
;
76 init
.num_parents
= mux
->num_parents
;
77 init
.flags
= mux
->flags
;
79 cpumux
->reg
= mux
->mux_reg
;
80 cpumux
->shift
= mux
->mux_shift
;
81 cpumux
->mask
= BIT(mux
->mux_width
) - 1;
82 cpumux
->regmap
= regmap
;
83 cpumux
->hw
.init
= &init
;
85 ret
= clk_hw_register(dev
, &cpumux
->hw
);
94 static void mtk_clk_unregister_cpumux(struct clk_hw
*hw
)
96 struct mtk_clk_cpumux
*cpumux
;
100 cpumux
= to_mtk_clk_cpumux(hw
);
102 clk_hw_unregister(hw
);
106 int mtk_clk_register_cpumuxes(struct device
*dev
, struct device_node
*node
,
107 const struct mtk_composite
*clks
, int num
,
108 struct clk_hw_onecell_data
*clk_data
)
112 struct regmap
*regmap
;
114 regmap
= device_node_to_regmap(node
);
115 if (IS_ERR(regmap
)) {
116 pr_err("Cannot find regmap for %pOF: %pe\n", node
, regmap
);
117 return PTR_ERR(regmap
);
120 for (i
= 0; i
< num
; i
++) {
121 const struct mtk_composite
*mux
= &clks
[i
];
123 if (!IS_ERR_OR_NULL(clk_data
->hws
[mux
->id
])) {
124 pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
129 hw
= mtk_clk_register_cpumux(dev
, mux
, regmap
);
131 pr_err("Failed to register clk %s: %pe\n", mux
->name
,
136 clk_data
->hws
[mux
->id
] = hw
;
143 const struct mtk_composite
*mux
= &clks
[i
];
145 if (IS_ERR_OR_NULL(clk_data
->hws
[mux
->id
]))
148 mtk_clk_unregister_cpumux(clk_data
->hws
[mux
->id
]);
149 clk_data
->hws
[mux
->id
] = ERR_PTR(-ENOENT
);
154 EXPORT_SYMBOL_GPL(mtk_clk_register_cpumuxes
);
156 void mtk_clk_unregister_cpumuxes(const struct mtk_composite
*clks
, int num
,
157 struct clk_hw_onecell_data
*clk_data
)
161 for (i
= num
; i
> 0; i
--) {
162 const struct mtk_composite
*mux
= &clks
[i
- 1];
164 if (IS_ERR_OR_NULL(clk_data
->hws
[mux
->id
]))
167 mtk_clk_unregister_cpumux(clk_data
->hws
[mux
->id
]);
168 clk_data
->hws
[mux
->id
] = ERR_PTR(-ENOENT
);
171 EXPORT_SYMBOL_GPL(mtk_clk_unregister_cpumuxes
);
173 MODULE_LICENSE("GPL");