aboutsummaryrefslogtreecommitdiff
path: root/drivers/clk/mediatek
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/mediatek')
-rw-r--r--drivers/clk/mediatek/clk-apmixed.c2
-rw-r--r--drivers/clk/mediatek/clk-cpumux.c69
-rw-r--r--drivers/clk/mediatek/clk-cpumux.h13
-rw-r--r--drivers/clk/mediatek/clk-gate.c148
-rw-r--r--drivers/clk/mediatek/clk-gate.h59
-rw-r--r--drivers/clk/mediatek/clk-mt2701.c5
-rw-r--r--drivers/clk/mediatek/clk-mt2712.c3
-rw-r--r--drivers/clk/mediatek/clk-mt6765.c3
-rw-r--r--drivers/clk/mediatek/clk-mt6779.c3
-rw-r--r--drivers/clk/mediatek/clk-mt6797.c3
-rw-r--r--drivers/clk/mediatek/clk-mt7622.c5
-rw-r--r--drivers/clk/mediatek/clk-mt7629.c5
-rw-r--r--drivers/clk/mediatek/clk-mt7986-apmixed.c4
-rw-r--r--drivers/clk/mediatek/clk-mt8135.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8167.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8173.c5
-rw-r--r--drivers/clk/mediatek/clk-mt8183.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8192.c39
-rw-r--r--drivers/clk/mediatek/clk-mt8195-apmixedsys.c30
-rw-r--r--drivers/clk/mediatek/clk-mt8195-apusys_pll.c25
-rw-r--r--drivers/clk/mediatek/clk-mt8195-cam.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-ccu.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-img.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-infra_ao.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-ipe.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-mfg.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-peri_ao.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-scp_adsp.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-topckgen.c69
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vdec.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vdo0.c20
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vdo1.c20
-rw-r--r--drivers/clk/mediatek/clk-mt8195-venc.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vpp0.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vpp1.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8195-wpe.c1
-rw-r--r--drivers/clk/mediatek/clk-mt8516.c3
-rw-r--r--drivers/clk/mediatek/clk-mtk.c304
-rw-r--r--drivers/clk/mediatek/clk-mtk.h105
-rw-r--r--drivers/clk/mediatek/clk-mux.c89
-rw-r--r--drivers/clk/mediatek/clk-mux.h17
-rw-r--r--drivers/clk/mediatek/clk-pll.c100
-rw-r--r--drivers/clk/mediatek/clk-pll.h57
-rw-r--r--drivers/clk/mediatek/reset.c3
45 files changed, 933 insertions, 298 deletions
diff --git a/drivers/clk/mediatek/clk-apmixed.c b/drivers/clk/mediatek/clk-apmixed.c
index caa9119413f1..a29339cc26c4 100644
--- a/drivers/clk/mediatek/clk-apmixed.c
+++ b/drivers/clk/mediatek/clk-apmixed.c
@@ -92,7 +92,7 @@ struct clk * __init mtk_clk_register_ref2usb_tx(const char *name,
clk = clk_register(NULL, &tx->hw);
if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n", name, PTR_ERR(clk));
+ pr_err("Failed to register clk %s: %pe\n", name, clk);
kfree(tx);
}
diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c
index e188018bc906..c11b3fae622e 100644
--- a/drivers/clk/mediatek/clk-cpumux.c
+++ b/drivers/clk/mediatek/clk-cpumux.c
@@ -5,13 +5,24 @@
*/
#include <linux/clk-provider.h>
+#include <linux/container_of.h>
+#include <linux/err.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include "clk-mtk.h"
#include "clk-cpumux.h"
+struct mtk_clk_cpumux {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ u32 reg;
+ u32 mask;
+ u8 shift;
+};
+
static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw)
{
return container_of(_hw, struct mtk_clk_cpumux, hw);
@@ -77,6 +88,21 @@ mtk_clk_register_cpumux(const struct mtk_composite *mux,
return clk;
}
+static void mtk_clk_unregister_cpumux(struct clk *clk)
+{
+ struct mtk_clk_cpumux *cpumux;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ cpumux = to_mtk_clk_cpumux(hw);
+
+ clk_unregister(clk);
+ kfree(cpumux);
+}
+
int mtk_clk_register_cpumuxes(struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data)
@@ -87,25 +113,58 @@ int mtk_clk_register_cpumuxes(struct device_node *node,
regmap = device_node_to_regmap(node);
if (IS_ERR(regmap)) {
- pr_err("Cannot find regmap for %pOF: %ld\n", node,
- PTR_ERR(regmap));
+ pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
return PTR_ERR(regmap);
}
for (i = 0; i < num; i++) {
const struct mtk_composite *mux = &clks[i];
+ if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
+ pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+ node, mux->id);
+ continue;
+ }
+
clk = mtk_clk_register_cpumux(mux, regmap);
if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- mux->name, PTR_ERR(clk));
- continue;
+ pr_err("Failed to register clk %s: %pe\n", mux->name, clk);
+ goto err;
}
clk_data->clks[mux->id] = clk;
}
return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_composite *mux = &clks[i];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+ continue;
+
+ mtk_clk_unregister_cpumux(clk_data->clks[mux->id]);
+ clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+ }
+
+ return PTR_ERR(clk);
+}
+
+void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
+ struct clk_onecell_data *clk_data)
+{
+ int i;
+
+ for (i = num; i > 0; i--) {
+ const struct mtk_composite *mux = &clks[i - 1];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+ continue;
+
+ mtk_clk_unregister_cpumux(clk_data->clks[mux->id]);
+ clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+ }
}
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-cpumux.h b/drivers/clk/mediatek/clk-cpumux.h
index 2aaf1afd4e5f..b07e89f7c283 100644
--- a/drivers/clk/mediatek/clk-cpumux.h
+++ b/drivers/clk/mediatek/clk-cpumux.h
@@ -7,16 +7,15 @@
#ifndef __DRV_CLK_CPUMUX_H
#define __DRV_CLK_CPUMUX_H
-struct mtk_clk_cpumux {
- struct clk_hw hw;
- struct regmap *regmap;
- u32 reg;
- u32 mask;
- u8 shift;
-};
+struct clk_onecell_data;
+struct device_node;
+struct mtk_composite;
int mtk_clk_register_cpumuxes(struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
+ struct clk_onecell_data *clk_data);
+
#endif /* __DRV_CLK_CPUMUX_H */
diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c
index 5d88b428565b..da52023f8455 100644
--- a/drivers/clk/mediatek/clk-gate.c
+++ b/drivers/clk/mediatek/clk-gate.c
@@ -4,18 +4,30 @@
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
-#include "clk-mtk.h"
#include "clk-gate.h"
+struct mtk_clk_gate {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ int set_ofs;
+ int clr_ofs;
+ int sta_ofs;
+ u8 bit;
+};
+
+static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
+{
+ return container_of(hw, struct mtk_clk_gate, hw);
+}
+
static u32 mtk_get_clockgating(struct clk_hw *hw)
{
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
@@ -140,17 +152,12 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
};
EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
-struct clk *mtk_clk_register_gate(
- const char *name,
- const char *parent_name,
- struct regmap *regmap,
- int set_ofs,
- int clr_ofs,
- int sta_ofs,
- u8 bit,
- const struct clk_ops *ops,
- unsigned long flags,
- struct device *dev)
+static struct clk *mtk_clk_register_gate(const char *name,
+ const char *parent_name,
+ struct regmap *regmap, int set_ofs,
+ int clr_ofs, int sta_ofs, u8 bit,
+ const struct clk_ops *ops,
+ unsigned long flags, struct device *dev)
{
struct mtk_clk_gate *cg;
struct clk *clk;
@@ -180,6 +187,107 @@ struct clk *mtk_clk_register_gate(
return clk;
}
-EXPORT_SYMBOL_GPL(mtk_clk_register_gate);
+
+static void mtk_clk_unregister_gate(struct clk *clk)
+{
+ struct mtk_clk_gate *cg;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ cg = to_mtk_clk_gate(hw);
+
+ clk_unregister(clk);
+ kfree(cg);
+}
+
+int mtk_clk_register_gates_with_dev(struct device_node *node,
+ const struct mtk_gate *clks, int num,
+ struct clk_onecell_data *clk_data,
+ struct device *dev)
+{
+ int i;
+ struct clk *clk;
+ struct regmap *regmap;
+
+ if (!clk_data)
+ return -ENOMEM;
+
+ regmap = device_node_to_regmap(node);
+ if (IS_ERR(regmap)) {
+ pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
+ return PTR_ERR(regmap);
+ }
+
+ for (i = 0; i < num; i++) {
+ const struct mtk_gate *gate = &clks[i];
+
+ if (!IS_ERR_OR_NULL(clk_data->clks[gate->id])) {
+ pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+ node, gate->id);
+ continue;
+ }
+
+ clk = mtk_clk_register_gate(gate->name, gate->parent_name,
+ regmap,
+ gate->regs->set_ofs,
+ gate->regs->clr_ofs,
+ gate->regs->sta_ofs,
+ gate->shift, gate->ops,
+ gate->flags, dev);
+
+ if (IS_ERR(clk)) {
+ pr_err("Failed to register clk %s: %pe\n", gate->name, clk);
+ goto err;
+ }
+
+ clk_data->clks[gate->id] = clk;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_gate *gate = &clks[i];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[gate->id]))
+ continue;
+
+ mtk_clk_unregister_gate(clk_data->clks[gate->id]);
+ clk_data->clks[gate->id] = ERR_PTR(-ENOENT);
+ }
+
+ return PTR_ERR(clk);
+}
+
+int mtk_clk_register_gates(struct device_node *node,
+ const struct mtk_gate *clks, int num,
+ struct clk_onecell_data *clk_data)
+{
+ return mtk_clk_register_gates_with_dev(node, clks, num, clk_data, NULL);
+}
+EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
+
+void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
+ struct clk_onecell_data *clk_data)
+{
+ int i;
+
+ if (!clk_data)
+ return;
+
+ for (i = num; i > 0; i--) {
+ const struct mtk_gate *gate = &clks[i - 1];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[gate->id]))
+ continue;
+
+ mtk_clk_unregister_gate(clk_data->clks[gate->id]);
+ clk_data->clks[gate->id] = ERR_PTR(-ENOENT);
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_gates);
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
index 3c3329ec54b7..6b5738826a22 100644
--- a/drivers/clk/mediatek/clk-gate.h
+++ b/drivers/clk/mediatek/clk-gate.h
@@ -7,41 +7,34 @@
#ifndef __DRV_CLK_GATE_H
#define __DRV_CLK_GATE_H
-#include <linux/regmap.h>
-#include <linux/clk-provider.h>
+#include <linux/types.h>
struct clk;
-
-struct mtk_clk_gate {
- struct clk_hw hw;
- struct regmap *regmap;
- int set_ofs;
- int clr_ofs;
- int sta_ofs;
- u8 bit;
-};
-
-static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
-{
- return container_of(hw, struct mtk_clk_gate, hw);
-}
+struct clk_onecell_data;
+struct clk_ops;
+struct device;
+struct device_node;
extern const struct clk_ops mtk_clk_gate_ops_setclr;
extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
extern const struct clk_ops mtk_clk_gate_ops_no_setclr;
extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv;
-struct clk *mtk_clk_register_gate(
- const char *name,
- const char *parent_name,
- struct regmap *regmap,
- int set_ofs,
- int clr_ofs,
- int sta_ofs,
- u8 bit,
- const struct clk_ops *ops,
- unsigned long flags,
- struct device *dev);
+struct mtk_gate_regs {
+ u32 sta_ofs;
+ u32 clr_ofs;
+ u32 set_ofs;
+};
+
+struct mtk_gate {
+ int id;
+ const char *name;
+ const char *parent_name;
+ const struct mtk_gate_regs *regs;
+ int shift;
+ const struct clk_ops *ops;
+ unsigned long flags;
+};
#define GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, \
_ops, _flags) { \
@@ -57,4 +50,16 @@ struct clk *mtk_clk_register_gate(
#define GATE_MTK(_id, _name, _parent, _regs, _shift, _ops) \
GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, _ops, 0)
+int mtk_clk_register_gates(struct device_node *node,
+ const struct mtk_gate *clks, int num,
+ struct clk_onecell_data *clk_data);
+
+int mtk_clk_register_gates_with_dev(struct device_node *node,
+ const struct mtk_gate *clks, int num,
+ struct clk_onecell_data *clk_data,
+ struct device *dev);
+
+void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
+ struct clk_onecell_data *clk_data);
+
#endif /* __DRV_CLK_GATE_H */
diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
index 695be0f77427..1eb3e4563c3f 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
@@ -10,9 +10,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include "clk-mtk.h"
-#include "clk-gate.h"
#include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt2701-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c
index a3bd9a107209..ff72b9ab945b 100644
--- a/drivers/clk/mediatek/clk-mt2712.c
+++ b/drivers/clk/mediatek/clk-mt2712.c
@@ -13,8 +13,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include "clk-mtk.h"
#include "clk-gate.h"
+#include "clk-pll.h"
+#include "clk-mtk.h"
#include <dt-bindings/clock/mt2712-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c
index d77ea5aff292..24829ca3bd1f 100644
--- a/drivers/clk/mediatek/clk-mt6765.c
+++ b/drivers/clk/mediatek/clk-mt6765.c
@@ -12,9 +12,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include "clk-mtk.h"
#include "clk-gate.h"
+#include "clk-mtk.h"
#include "clk-mux.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt6765-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c
index 9825385c9f94..7b61664da18f 100644
--- a/drivers/clk/mediatek/clk-mt6779.c
+++ b/drivers/clk/mediatek/clk-mt6779.c
@@ -10,9 +10,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
-#include "clk-gate.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt6779-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c
index 428eb24ffec5..02259e81625a 100644
--- a/drivers/clk/mediatek/clk-mt6797.c
+++ b/drivers/clk/mediatek/clk-mt6797.c
@@ -9,8 +9,9 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include "clk-mtk.h"
#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt6797-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt7622.c b/drivers/clk/mediatek/clk-mt7622.c
index ef5947e15c75..0e1fb30a1e98 100644
--- a/drivers/clk/mediatek/clk-mt7622.c
+++ b/drivers/clk/mediatek/clk-mt7622.c
@@ -11,9 +11,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include "clk-mtk.h"
-#include "clk-gate.h"
#include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt7622-clk.h>
#include <linux/clk.h> /* for consumer */
diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c
index a0ee079670c7..c0e023bf31eb 100644
--- a/drivers/clk/mediatek/clk-mt7629.c
+++ b/drivers/clk/mediatek/clk-mt7629.c
@@ -12,9 +12,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include "clk-mtk.h"
-#include "clk-gate.h"
#include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt7629-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt7986-apmixed.c b/drivers/clk/mediatek/clk-mt7986-apmixed.c
index 98ec3887585f..21d4c82e782a 100644
--- a/drivers/clk/mediatek/clk-mt7986-apmixed.c
+++ b/drivers/clk/mediatek/clk-mt7986-apmixed.c
@@ -10,9 +10,11 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include "clk-mtk.h"
+
#include "clk-gate.h"
+#include "clk-mtk.h"
#include "clk-mux.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt7986-clk.h>
#include <linux/clk.h>
diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c
index 9b4b645aea99..09ad272d51f1 100644
--- a/drivers/clk/mediatek/clk-mt8135.c
+++ b/drivers/clk/mediatek/clk-mt8135.c
@@ -11,8 +11,9 @@
#include <linux/mfd/syscon.h>
#include <dt-bindings/clock/mt8135-clk.h>
-#include "clk-mtk.h"
#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
static DEFINE_SPINLOCK(mt8135_clk_lock);
diff --git a/drivers/clk/mediatek/clk-mt8167.c b/drivers/clk/mediatek/clk-mt8167.c
index e5ea10e31799..812b33a57530 100644
--- a/drivers/clk/mediatek/clk-mt8167.c
+++ b/drivers/clk/mediatek/clk-mt8167.c
@@ -12,8 +12,9 @@
#include <linux/slab.h>
#include <linux/mfd/syscon.h>
-#include "clk-mtk.h"
#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt8167-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
index 8f898ac476c0..46b7655feeaa 100644
--- a/drivers/clk/mediatek/clk-mt8173.c
+++ b/drivers/clk/mediatek/clk-mt8173.c
@@ -8,9 +8,10 @@
#include <linux/of.h>
#include <linux/of_address.h>
-#include "clk-mtk.h"
-#include "clk-gate.h"
#include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt8173-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c
index 5046852eb0fd..68496554dd3d 100644
--- a/drivers/clk/mediatek/clk-mt8183.c
+++ b/drivers/clk/mediatek/clk-mt8183.c
@@ -11,9 +11,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
-#include "clk-gate.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt8183-clk.h>
diff --git a/drivers/clk/mediatek/clk-mt8192.c b/drivers/clk/mediatek/clk-mt8192.c
index cbc7c6dbe0f4..ab27cd66b866 100644
--- a/drivers/clk/mediatek/clk-mt8192.c
+++ b/drivers/clk/mediatek/clk-mt8192.c
@@ -12,9 +12,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
-#include "clk-gate.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt8192-clk.h>
@@ -1236,9 +1237,17 @@ static int clk_mt8192_infra_probe(struct platform_device *pdev)
r = mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), clk_data);
if (r)
- return r;
+ goto free_clk_data;
+
+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ if (r)
+ goto free_clk_data;
- return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ return r;
+
+free_clk_data:
+ mtk_free_clk_data(clk_data);
+ return r;
}
static int clk_mt8192_peri_probe(struct platform_device *pdev)
@@ -1253,9 +1262,17 @@ static int clk_mt8192_peri_probe(struct platform_device *pdev)
r = mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), clk_data);
if (r)
- return r;
+ goto free_clk_data;
+
+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ if (r)
+ goto free_clk_data;
+
+ return r;
- return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+free_clk_data:
+ mtk_free_clk_data(clk_data);
+ return r;
}
static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
@@ -1271,9 +1288,17 @@ static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
if (r)
- return r;
+ goto free_clk_data;
- return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ if (r)
+ goto free_clk_data;
+
+ return r;
+
+free_clk_data:
+ mtk_free_clk_data(clk_data);
+ return r;
}
static const struct of_device_id of_match_clk_mt8192[] = {
diff --git a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
index 6156ceeed71e..eecc7035a56a 100644
--- a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
@@ -5,6 +5,7 @@
#include "clk-gate.h"
#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt8195-clk.h>
#include <linux/of_device.h>
@@ -119,24 +120,47 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
- r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+ r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
if (r)
goto free_apmixed_data;
+ r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+ if (r)
+ goto unregister_plls;
+
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
- goto free_apmixed_data;
+ goto unregister_gates;
+
+ platform_set_drvdata(pdev, clk_data);
return r;
+unregister_gates:
+ mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+unregister_plls:
+ mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
free_apmixed_data:
mtk_free_clk_data(clk_data);
return r;
}
+static int clk_mt8195_apmixed_remove(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+ mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
static struct platform_driver clk_mt8195_apmixed_drv = {
.probe = clk_mt8195_apmixed_probe,
+ .remove = clk_mt8195_apmixed_remove,
.driver = {
.name = "clk-mt8195-apmixed",
.of_match_table = of_match_clk_mt8195_apmixed,
diff --git a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c
index f1c84186346e..8cd88dfc3283 100644
--- a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c
+++ b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c
@@ -4,6 +4,7 @@
// Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt8195-clk.h>
#include <linux/clk-provider.h>
@@ -65,18 +66,37 @@ static int clk_mt8195_apusys_pll_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
- r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
if (r)
goto free_apusys_pll_data;
+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+ if (r)
+ goto unregister_plls;
+
+ platform_set_drvdata(pdev, clk_data);
+
return r;
+unregister_plls:
+ mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
free_apusys_pll_data:
mtk_free_clk_data(clk_data);
return r;
}
+static int clk_mt8195_apusys_pll_remove(struct platform_device *pdev)
+{
+ struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = {
{ .compatible = "mediatek,mt8195-apusys_pll", },
{}
@@ -84,6 +104,7 @@ static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = {
static struct platform_driver clk_mt8195_apusys_pll_drv = {
.probe = clk_mt8195_apusys_pll_probe,
+ .remove = clk_mt8195_apusys_pll_remove,
.driver = {
.name = "clk-mt8195-apusys_pll",
.of_match_table = of_match_clk_mt8195_apusys_pll,
diff --git a/drivers/clk/mediatek/clk-mt8195-cam.c b/drivers/clk/mediatek/clk-mt8195-cam.c
index 3d261fc3848e..e4d00fe6e757 100644
--- a/drivers/clk/mediatek/clk-mt8195-cam.c
+++ b/drivers/clk/mediatek/clk-mt8195-cam.c
@@ -134,6 +134,7 @@ static const struct of_device_id of_match_clk_mt8195_cam[] = {
static struct platform_driver clk_mt8195_cam_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-cam",
.of_match_table = of_match_clk_mt8195_cam,
diff --git a/drivers/clk/mediatek/clk-mt8195-ccu.c b/drivers/clk/mediatek/clk-mt8195-ccu.c
index f846f1d73605..4e326b6301ba 100644
--- a/drivers/clk/mediatek/clk-mt8195-ccu.c
+++ b/drivers/clk/mediatek/clk-mt8195-ccu.c
@@ -42,6 +42,7 @@ static const struct of_device_id of_match_clk_mt8195_ccu[] = {
static struct platform_driver clk_mt8195_ccu_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-ccu",
.of_match_table = of_match_clk_mt8195_ccu,
diff --git a/drivers/clk/mediatek/clk-mt8195-img.c b/drivers/clk/mediatek/clk-mt8195-img.c
index 22b52a8f15fe..12f5c436d075 100644
--- a/drivers/clk/mediatek/clk-mt8195-img.c
+++ b/drivers/clk/mediatek/clk-mt8195-img.c
@@ -88,6 +88,7 @@ static const struct of_device_id of_match_clk_mt8195_img[] = {
static struct platform_driver clk_mt8195_img_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-img",
.of_match_table = of_match_clk_mt8195_img,
diff --git a/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c
index 4ab312eb26a5..fbc809d05072 100644
--- a/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c
+++ b/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c
@@ -58,6 +58,7 @@ static const struct of_device_id of_match_clk_mt8195_imp_iic_wrap[] = {
static struct platform_driver clk_mt8195_imp_iic_wrap_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-imp_iic_wrap",
.of_match_table = of_match_clk_mt8195_imp_iic_wrap,
diff --git a/drivers/clk/mediatek/clk-mt8195-infra_ao.c b/drivers/clk/mediatek/clk-mt8195-infra_ao.c
index 5f9b69967459..8ebe3b9415c4 100644
--- a/drivers/clk/mediatek/clk-mt8195-infra_ao.c
+++ b/drivers/clk/mediatek/clk-mt8195-infra_ao.c
@@ -198,6 +198,7 @@ static const struct of_device_id of_match_clk_mt8195_infra_ao[] = {
static struct platform_driver clk_mt8195_infra_ao_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-infra_ao",
.of_match_table = of_match_clk_mt8195_infra_ao,
diff --git a/drivers/clk/mediatek/clk-mt8195-ipe.c b/drivers/clk/mediatek/clk-mt8195-ipe.c
index fc1d42b6ac84..b0d745cf7752 100644
--- a/drivers/clk/mediatek/clk-mt8195-ipe.c
+++ b/drivers/clk/mediatek/clk-mt8195-ipe.c
@@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt8195_ipe[] = {
static struct platform_driver clk_mt8195_ipe_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-ipe",
.of_match_table = of_match_clk_mt8195_ipe,
diff --git a/drivers/clk/mediatek/clk-mt8195-mfg.c b/drivers/clk/mediatek/clk-mt8195-mfg.c
index aca6d9c0837c..9411c556a5a9 100644
--- a/drivers/clk/mediatek/clk-mt8195-mfg.c
+++ b/drivers/clk/mediatek/clk-mt8195-mfg.c
@@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_mfg[] = {
static struct platform_driver clk_mt8195_mfg_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-mfg",
.of_match_table = of_match_clk_mt8195_mfg,
diff --git a/drivers/clk/mediatek/clk-mt8195-peri_ao.c b/drivers/clk/mediatek/clk-mt8195-peri_ao.c
index 907a92b22de8..2f6b3bb657db 100644
--- a/drivers/clk/mediatek/clk-mt8195-peri_ao.c
+++ b/drivers/clk/mediatek/clk-mt8195-peri_ao.c
@@ -54,6 +54,7 @@ static const struct of_device_id of_match_clk_mt8195_peri_ao[] = {
static struct platform_driver clk_mt8195_peri_ao_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-peri_ao",
.of_match_table = of_match_clk_mt8195_peri_ao,
diff --git a/drivers/clk/mediatek/clk-mt8195-scp_adsp.c b/drivers/clk/mediatek/clk-mt8195-scp_adsp.c
index 26b4846c5894..e16c383f631b 100644
--- a/drivers/clk/mediatek/clk-mt8195-scp_adsp.c
+++ b/drivers/clk/mediatek/clk-mt8195-scp_adsp.c
@@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_scp_adsp[] = {
static struct platform_driver clk_mt8195_scp_adsp_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-scp_adsp",
.of_match_table = of_match_clk_mt8195_scp_adsp,
diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c
index 3e2aba9c40bb..b602fcd7f1d1 100644
--- a/drivers/clk/mediatek/clk-mt8195-topckgen.c
+++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c
@@ -1239,32 +1239,79 @@ static int clk_mt8195_topck_probe(struct platform_device *pdev)
goto free_top_data;
}
- mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
- top_clk_data);
- mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
- mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
- &mt8195_clk_lock, top_clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
- &mt8195_clk_lock, top_clk_data);
- mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
- &mt8195_clk_lock, top_clk_data);
- r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+ r = mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
+ top_clk_data);
if (r)
goto free_top_data;
+ r = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
+ if (r)
+ goto unregister_fixed_clks;
+
+ r = mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
+ &mt8195_clk_lock, top_clk_data);
+ if (r)
+ goto unregister_factors;
+
+ r = mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
+ &mt8195_clk_lock, top_clk_data);
+ if (r)
+ goto unregister_muxes;
+
+ r = mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
+ &mt8195_clk_lock, top_clk_data);
+ if (r)
+ goto unregister_composite_muxes;
+
+ r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+ if (r)
+ goto unregister_composite_divs;
+
r = of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data);
if (r)
- goto free_top_data;
+ goto unregister_gates;
+
+ platform_set_drvdata(pdev, top_clk_data);
return r;
+unregister_gates:
+ mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+unregister_composite_divs:
+ mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data);
+unregister_composite_muxes:
+ mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data);
+unregister_muxes:
+ mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data);
+unregister_factors:
+ mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
+unregister_fixed_clks:
+ mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data);
free_top_data:
mtk_free_clk_data(top_clk_data);
return r;
}
+static int clk_mt8195_topck_remove(struct platform_device *pdev)
+{
+ struct clk_onecell_data *top_clk_data = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+ mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data);
+ mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data);
+ mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data);
+ mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
+ mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data);
+ mtk_free_clk_data(top_clk_data);
+
+ return 0;
+}
+
static struct platform_driver clk_mt8195_topck_drv = {
.probe = clk_mt8195_topck_probe,
+ .remove = clk_mt8195_topck_remove,
.driver = {
.name = "clk-mt8195-topck",
.of_match_table = of_match_clk_mt8195_topck,
diff --git a/drivers/clk/mediatek/clk-mt8195-vdec.c b/drivers/clk/mediatek/clk-mt8195-vdec.c
index a1df04f42a90..a1446b666385 100644
--- a/drivers/clk/mediatek/clk-mt8195-vdec.c
+++ b/drivers/clk/mediatek/clk-mt8195-vdec.c
@@ -96,6 +96,7 @@ static const struct of_device_id of_match_clk_mt8195_vdec[] = {
static struct platform_driver clk_mt8195_vdec_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-vdec",
.of_match_table = of_match_clk_mt8195_vdec,
diff --git a/drivers/clk/mediatek/clk-mt8195-vdo0.c b/drivers/clk/mediatek/clk-mt8195-vdo0.c
index f7ff7618c714..3bc7ed19d550 100644
--- a/drivers/clk/mediatek/clk-mt8195-vdo0.c
+++ b/drivers/clk/mediatek/clk-mt8195-vdo0.c
@@ -105,17 +105,35 @@ static int clk_mt8195_vdo0_probe(struct platform_device *pdev)
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
- goto free_vdo0_data;
+ goto unregister_gates;
+
+ platform_set_drvdata(pdev, clk_data);
return r;
+unregister_gates:
+ mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data);
free_vdo0_data:
mtk_free_clk_data(clk_data);
return r;
}
+static int clk_mt8195_vdo0_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
static struct platform_driver clk_mt8195_vdo0_drv = {
.probe = clk_mt8195_vdo0_probe,
+ .remove = clk_mt8195_vdo0_remove,
.driver = {
.name = "clk-mt8195-vdo0",
},
diff --git a/drivers/clk/mediatek/clk-mt8195-vdo1.c b/drivers/clk/mediatek/clk-mt8195-vdo1.c
index 03df8eae8838..90c738a85ff1 100644
--- a/drivers/clk/mediatek/clk-mt8195-vdo1.c
+++ b/drivers/clk/mediatek/clk-mt8195-vdo1.c
@@ -122,17 +122,35 @@ static int clk_mt8195_vdo1_probe(struct platform_device *pdev)
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
- goto free_vdo1_data;
+ goto unregister_gates;
+
+ platform_set_drvdata(pdev, clk_data);
return r;
+unregister_gates:
+ mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data);
free_vdo1_data:
mtk_free_clk_data(clk_data);
return r;
}
+static int clk_mt8195_vdo1_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
static struct platform_driver clk_mt8195_vdo1_drv = {
.probe = clk_mt8195_vdo1_probe,
+ .remove = clk_mt8195_vdo1_remove,
.driver = {
.name = "clk-mt8195-vdo1",
},
diff --git a/drivers/clk/mediatek/clk-mt8195-venc.c b/drivers/clk/mediatek/clk-mt8195-venc.c
index 7339851a0856..622f57804f96 100644
--- a/drivers/clk/mediatek/clk-mt8195-venc.c
+++ b/drivers/clk/mediatek/clk-mt8195-venc.c
@@ -61,6 +61,7 @@ static const struct of_device_id of_match_clk_mt8195_venc[] = {
static struct platform_driver clk_mt8195_venc_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-venc",
.of_match_table = of_match_clk_mt8195_venc,
diff --git a/drivers/clk/mediatek/clk-mt8195-vpp0.c b/drivers/clk/mediatek/clk-mt8195-vpp0.c
index c3241466a8d0..bf2939c3a023 100644
--- a/drivers/clk/mediatek/clk-mt8195-vpp0.c
+++ b/drivers/clk/mediatek/clk-mt8195-vpp0.c
@@ -102,6 +102,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp0[] = {
static struct platform_driver clk_mt8195_vpp0_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-vpp0",
.of_match_table = of_match_clk_mt8195_vpp0,
diff --git a/drivers/clk/mediatek/clk-mt8195-vpp1.c b/drivers/clk/mediatek/clk-mt8195-vpp1.c
index ce0b9a40a179..ffd52c762890 100644
--- a/drivers/clk/mediatek/clk-mt8195-vpp1.c
+++ b/drivers/clk/mediatek/clk-mt8195-vpp1.c
@@ -100,6 +100,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp1[] = {
static struct platform_driver clk_mt8195_vpp1_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-vpp1",
.of_match_table = of_match_clk_mt8195_vpp1,
diff --git a/drivers/clk/mediatek/clk-mt8195-wpe.c b/drivers/clk/mediatek/clk-mt8195-wpe.c
index 274d60838d8e..b483fab10e18 100644
--- a/drivers/clk/mediatek/clk-mt8195-wpe.c
+++ b/drivers/clk/mediatek/clk-mt8195-wpe.c
@@ -135,6 +135,7 @@ static const struct of_device_id of_match_clk_mt8195_wpe[] = {
static struct platform_driver clk_mt8195_wpe_drv = {
.probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-wpe",
.of_match_table = of_match_clk_mt8195_wpe,
diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c
index 9d4261ecc760..a37143f920ce 100644
--- a/drivers/clk/mediatek/clk-mt8516.c
+++ b/drivers/clk/mediatek/clk-mt8516.c
@@ -11,8 +11,9 @@
#include <linux/slab.h>
#include <linux/mfd/syscon.h>
-#include "clk-mtk.h"
#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
#include <dt-bindings/clock/mt8516-clk.h>
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index 8d5791b3f460..b4063261cf56 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -4,17 +4,16 @@
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
-#include <linux/of.h>
-#include <linux/of_address.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/clkdev.h>
-#include <linux/module.h>
#include <linux/mfd/syscon.h>
-#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
#include "clk-mtk.h"
#include "clk-gate.h"
@@ -54,112 +53,135 @@ void mtk_free_clk_data(struct clk_onecell_data *clk_data)
kfree(clk_data);
}
-void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
- int num, struct clk_onecell_data *clk_data)
+int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+ struct clk_onecell_data *clk_data)
{
int i;
struct clk *clk;
+ if (!clk_data)
+ return -ENOMEM;
+
for (i = 0; i < num; i++) {
const struct mtk_fixed_clk *rc = &clks[i];
- if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
+ if (!IS_ERR_OR_NULL(clk_data->clks[rc->id])) {
+ pr_warn("Trying to register duplicate clock ID: %d\n", rc->id);
continue;
+ }
clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
rc->rate);
if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- rc->name, PTR_ERR(clk));
- continue;
+ pr_err("Failed to register clk %s: %pe\n", rc->name, clk);
+ goto err;
}
- if (clk_data)
- clk_data->clks[rc->id] = clk;
+ clk_data->clks[rc->id] = clk;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_fixed_clk *rc = &clks[i];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
+ continue;
+
+ clk_unregister_fixed_rate(clk_data->clks[rc->id]);
+ clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
}
+
+ return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_fixed_clks);
-void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
- int num, struct clk_onecell_data *clk_data)
+void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+ struct clk_onecell_data *clk_data)
{
int i;
- struct clk *clk;
- for (i = 0; i < num; i++) {
- const struct mtk_fixed_factor *ff = &clks[i];
-
- if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
- continue;
+ if (!clk_data)
+ return;
- clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
- CLK_SET_RATE_PARENT, ff->mult, ff->div);
+ for (i = num; i > 0; i--) {
+ const struct mtk_fixed_clk *rc = &clks[i - 1];
- if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- ff->name, PTR_ERR(clk));
+ if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
continue;
- }
- if (clk_data)
- clk_data->clks[ff->id] = clk;
+ clk_unregister_fixed_rate(clk_data->clks[rc->id]);
+ clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
}
}
-EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_fixed_clks);
-int mtk_clk_register_gates_with_dev(struct device_node *node,
- const struct mtk_gate *clks,
- int num, struct clk_onecell_data *clk_data,
- struct device *dev)
+int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
+ struct clk_onecell_data *clk_data)
{
int i;
struct clk *clk;
- struct regmap *regmap;
if (!clk_data)
return -ENOMEM;
- regmap = device_node_to_regmap(node);
- if (IS_ERR(regmap)) {
- pr_err("Cannot find regmap for %pOF: %ld\n", node,
- PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
-
for (i = 0; i < num; i++) {
- const struct mtk_gate *gate = &clks[i];
+ const struct mtk_fixed_factor *ff = &clks[i];
- if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
+ if (!IS_ERR_OR_NULL(clk_data->clks[ff->id])) {
+ pr_warn("Trying to register duplicate clock ID: %d\n", ff->id);
continue;
+ }
- clk = mtk_clk_register_gate(gate->name, gate->parent_name,
- regmap,
- gate->regs->set_ofs,
- gate->regs->clr_ofs,
- gate->regs->sta_ofs,
- gate->shift, gate->ops, gate->flags, dev);
+ clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
+ CLK_SET_RATE_PARENT, ff->mult, ff->div);
if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- gate->name, PTR_ERR(clk));
- continue;
+ pr_err("Failed to register clk %s: %pe\n", ff->name, clk);
+ goto err;
}
- clk_data->clks[gate->id] = clk;
+ clk_data->clks[ff->id] = clk;
}
return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_fixed_factor *ff = &clks[i];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
+ continue;
+
+ clk_unregister_fixed_factor(clk_data->clks[ff->id]);
+ clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
+ }
+
+ return PTR_ERR(clk);
}
+EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
-int mtk_clk_register_gates(struct device_node *node,
- const struct mtk_gate *clks,
- int num, struct clk_onecell_data *clk_data)
+void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
+ struct clk_onecell_data *clk_data)
{
- return mtk_clk_register_gates_with_dev(node,
- clks, num, clk_data, NULL);
+ int i;
+
+ if (!clk_data)
+ return;
+
+ for (i = num; i > 0; i--) {
+ const struct mtk_fixed_factor *ff = &clks[i - 1];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
+ continue;
+
+ clk_unregister_fixed_factor(clk_data->clks[ff->id]);
+ clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
+ }
}
-EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors);
struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
void __iomem *base, spinlock_t *lock)
@@ -248,58 +270,161 @@ err_out:
return ERR_PTR(ret);
}
-void mtk_clk_register_composites(const struct mtk_composite *mcs,
- int num, void __iomem *base, spinlock_t *lock,
- struct clk_onecell_data *clk_data)
+static void mtk_clk_unregister_composite(struct clk *clk)
+{
+ struct clk_hw *hw;
+ struct clk_composite *composite;
+ struct clk_mux *mux = NULL;
+ struct clk_gate *gate = NULL;
+ struct clk_divider *div = NULL;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ composite = to_clk_composite(hw);
+ if (composite->mux_hw)
+ mux = to_clk_mux(composite->mux_hw);
+ if (composite->gate_hw)
+ gate = to_clk_gate(composite->gate_hw);
+ if (composite->rate_hw)
+ div = to_clk_divider(composite->rate_hw);
+
+ clk_unregister_composite(clk);
+ kfree(div);
+ kfree(gate);
+ kfree(mux);
+}
+
+int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
+ void __iomem *base, spinlock_t *lock,
+ struct clk_onecell_data *clk_data)
{
struct clk *clk;
int i;
+ if (!clk_data)
+ return -ENOMEM;
+
for (i = 0; i < num; i++) {
const struct mtk_composite *mc = &mcs[i];
- if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
+ if (!IS_ERR_OR_NULL(clk_data->clks[mc->id])) {
+ pr_warn("Trying to register duplicate clock ID: %d\n",
+ mc->id);
continue;
+ }
clk = mtk_clk_register_composite(mc, base, lock);
if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- mc->name, PTR_ERR(clk));
- continue;
+ pr_err("Failed to register clk %s: %pe\n", mc->name, clk);
+ goto err;
}
- if (clk_data)
- clk_data->clks[mc->id] = clk;
+ clk_data->clks[mc->id] = clk;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_composite *mc = &mcs[i];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mcs->id]))
+ continue;
+
+ mtk_clk_unregister_composite(clk_data->clks[mc->id]);
+ clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
}
+
+ return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_composites);
-void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
- int num, void __iomem *base, spinlock_t *lock,
- struct clk_onecell_data *clk_data)
+void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
+ struct clk_onecell_data *clk_data)
+{
+ int i;
+
+ if (!clk_data)
+ return;
+
+ for (i = num; i > 0; i--) {
+ const struct mtk_composite *mc = &mcs[i - 1];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mc->id]))
+ continue;
+
+ mtk_clk_unregister_composite(clk_data->clks[mc->id]);
+ clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites);
+
+int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
+ void __iomem *base, spinlock_t *lock,
+ struct clk_onecell_data *clk_data)
{
struct clk *clk;
int i;
+ if (!clk_data)
+ return -ENOMEM;
+
for (i = 0; i < num; i++) {
const struct mtk_clk_divider *mcd = &mcds[i];
- if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
+ if (!IS_ERR_OR_NULL(clk_data->clks[mcd->id])) {
+ pr_warn("Trying to register duplicate clock ID: %d\n",
+ mcd->id);
continue;
+ }
clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
mcd->flags, base + mcd->div_reg, mcd->div_shift,
mcd->div_width, mcd->clk_divider_flags, lock);
if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- mcd->name, PTR_ERR(clk));
- continue;
+ pr_err("Failed to register clk %s: %pe\n", mcd->name, clk);
+ goto err;
}
- if (clk_data)
- clk_data->clks[mcd->id] = clk;
+ clk_data->clks[mcd->id] = clk;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_clk_divider *mcd = &mcds[i];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
+ continue;
+
+ mtk_clk_unregister_composite(clk_data->clks[mcd->id]);
+ clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
+ }
+
+ return PTR_ERR(clk);
+}
+
+void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
+ struct clk_onecell_data *clk_data)
+{
+ int i;
+
+ if (!clk_data)
+ return;
+
+ for (i = num; i > 0; i--) {
+ const struct mtk_clk_divider *mcd = &mcds[i - 1];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
+ continue;
+
+ clk_unregister_divider(clk_data->clks[mcd->id]);
+ clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
}
}
@@ -324,13 +449,30 @@ int mtk_clk_simple_probe(struct platform_device *pdev)
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
- goto free_data;
+ goto unregister_clks;
+
+ platform_set_drvdata(pdev, clk_data);
return r;
+unregister_clks:
+ mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
free_data:
mtk_free_clk_data(clk_data);
return r;
}
+int mtk_clk_simple_remove(struct platform_device *pdev)
+{
+ const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev);
+ struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index 0ff289d93452..bf6565aa7319 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -7,19 +7,19 @@
#ifndef __DRV_CLK_MTK_H
#define __DRV_CLK_MTK_H
-#include <linux/regmap.h>
-#include <linux/bitops.h>
#include <linux/clk-provider.h>
-#include <linux/platform_device.h>
-
-struct clk;
-struct clk_onecell_data;
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
#define MAX_MUX_GATE_BIT 31
#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1)
#define MHZ (1000 * 1000)
+struct platform_device;
+
struct mtk_fixed_clk {
int id;
const char *name;
@@ -34,8 +34,10 @@ struct mtk_fixed_clk {
.rate = _rate, \
}
-void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
- int num, struct clk_onecell_data *clk_data);
+int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+ struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+ struct clk_onecell_data *clk_data);
struct mtk_fixed_factor {
int id;
@@ -53,8 +55,10 @@ struct mtk_fixed_factor {
.div = _div, \
}
-void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
- int num, struct clk_onecell_data *clk_data);
+int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
+ struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
+ struct clk_onecell_data *clk_data);
struct mtk_composite {
int id;
@@ -146,34 +150,11 @@ struct mtk_composite {
struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
void __iomem *base, spinlock_t *lock);
-void mtk_clk_register_composites(const struct mtk_composite *mcs,
- int num, void __iomem *base, spinlock_t *lock,
- struct clk_onecell_data *clk_data);
-
-struct mtk_gate_regs {
- u32 sta_ofs;
- u32 clr_ofs;
- u32 set_ofs;
-};
-
-struct mtk_gate {
- int id;
- const char *name;
- const char *parent_name;
- const struct mtk_gate_regs *regs;
- int shift;
- const struct clk_ops *ops;
- unsigned long flags;
-};
-
-int mtk_clk_register_gates(struct device_node *node,
- const struct mtk_gate *clks, int num,
- struct clk_onecell_data *clk_data);
-
-int mtk_clk_register_gates_with_dev(struct device_node *node,
- const struct mtk_gate *clks,
- int num, struct clk_onecell_data *clk_data,
- struct device *dev);
+int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
+ void __iomem *base, spinlock_t *lock,
+ struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
+ struct clk_onecell_data *clk_data);
struct mtk_clk_divider {
int id;
@@ -197,52 +178,15 @@ struct mtk_clk_divider {
.div_width = _width, \
}
-void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
- int num, void __iomem *base, spinlock_t *lock,
- struct clk_onecell_data *clk_data);
+int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
+ void __iomem *base, spinlock_t *lock,
+ struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
+ struct clk_onecell_data *clk_data);
struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
void mtk_free_clk_data(struct clk_onecell_data *clk_data);
-#define HAVE_RST_BAR BIT(0)
-#define PLL_AO BIT(1)
-
-struct mtk_pll_div_table {
- u32 div;
- unsigned long freq;
-};
-
-struct mtk_pll_data {
- int id;
- const char *name;
- u32 reg;
- u32 pwr_reg;
- u32 en_mask;
- u32 pd_reg;
- u32 tuner_reg;
- u32 tuner_en_reg;
- u8 tuner_en_bit;
- int pd_shift;
- unsigned int flags;
- const struct clk_ops *ops;
- u32 rst_bar_mask;
- unsigned long fmin;
- unsigned long fmax;
- int pcwbits;
- int pcwibits;
- u32 pcw_reg;
- int pcw_shift;
- u32 pcw_chg_reg;
- const struct mtk_pll_div_table *div_table;
- const char *parent_name;
- u32 en_reg;
- u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
-};
-
-void mtk_clk_register_plls(struct device_node *node,
- const struct mtk_pll_data *plls, int num_plls,
- struct clk_onecell_data *clk_data);
-
struct clk *mtk_clk_register_ref2usb_tx(const char *name,
const char *parent_name, void __iomem *reg);
@@ -258,5 +202,6 @@ struct mtk_clk_desc {
};
int mtk_clk_simple_probe(struct platform_device *pdev);
+int mtk_clk_simple_remove(struct platform_device *pdev);
#endif /* __DRV_CLK_MTK_H */
diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c
index 6d3a50eb7d6f..21ad5a4afd65 100644
--- a/drivers/clk/mediatek/clk-mux.c
+++ b/drivers/clk/mediatek/clk-mux.c
@@ -4,15 +4,26 @@
* Author: Owen Chen <owen.chen@mediatek.com>
*/
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/compiler_types.h>
+#include <linux/container_of.h>
+#include <linux/err.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
-#include "clk-mtk.h"
#include "clk-mux.h"
+struct mtk_clk_mux {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ const struct mtk_mux *data;
+ spinlock_t *lock;
+ bool reparent;
+};
+
static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
{
return container_of(hw, struct mtk_clk_mux, hw);
@@ -164,6 +175,21 @@ static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
return clk;
}
+static void mtk_clk_unregister_mux(struct clk *clk)
+{
+ struct mtk_clk_mux *mux;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ mux = to_mtk_clk_mux(hw);
+
+ clk_unregister(clk);
+ kfree(mux);
+}
+
int mtk_clk_register_muxes(const struct mtk_mux *muxes,
int num, struct device_node *node,
spinlock_t *lock,
@@ -175,29 +201,64 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes,
regmap = device_node_to_regmap(node);
if (IS_ERR(regmap)) {
- pr_err("Cannot find regmap for %pOF: %ld\n", node,
- PTR_ERR(regmap));
+ pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
return PTR_ERR(regmap);
}
for (i = 0; i < num; i++) {
const struct mtk_mux *mux = &muxes[i];
- if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
- clk = mtk_clk_register_mux(mux, regmap, lock);
+ if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
+ pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+ node, mux->id);
+ continue;
+ }
- if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- mux->name, PTR_ERR(clk));
- continue;
- }
+ clk = mtk_clk_register_mux(mux, regmap, lock);
- clk_data->clks[mux->id] = clk;
+ if (IS_ERR(clk)) {
+ pr_err("Failed to register clk %s: %pe\n", mux->name, clk);
+ goto err;
}
+
+ clk_data->clks[mux->id] = clk;
}
return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_mux *mux = &muxes[i];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+ continue;
+
+ mtk_clk_unregister_mux(clk_data->clks[mux->id]);
+ clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+ }
+
+ return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_muxes);
+void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num,
+ struct clk_onecell_data *clk_data)
+{
+ int i;
+
+ if (!clk_data)
+ return;
+
+ for (i = num; i > 0; i--) {
+ const struct mtk_mux *mux = &muxes[i - 1];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+ continue;
+
+ mtk_clk_unregister_mux(clk_data->clks[mux->id]);
+ clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_muxes);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h
index 27841d649118..903a3c937959 100644
--- a/drivers/clk/mediatek/clk-mux.h
+++ b/drivers/clk/mediatek/clk-mux.h
@@ -7,15 +7,13 @@
#ifndef __DRV_CLK_MTK_MUX_H
#define __DRV_CLK_MTK_MUX_H
-#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
-struct mtk_clk_mux {
- struct clk_hw hw;
- struct regmap *regmap;
- const struct mtk_mux *data;
- spinlock_t *lock;
- bool reparent;
-};
+struct clk;
+struct clk_onecell_data;
+struct clk_ops;
+struct device_node;
struct mtk_mux {
int id;
@@ -88,4 +86,7 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes,
spinlock_t *lock,
struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num,
+ struct clk_onecell_data *clk_data);
+
#endif /* __DRV_CLK_MTK_MUX_H */
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
index 60d7ffa0b924..ccaa2085ab4d 100644
--- a/drivers/clk/mediatek/clk-pll.c
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -4,15 +4,18 @@
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
-#include <linux/of.h>
-#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of_address.h>
#include <linux/slab.h>
-#include <linux/clkdev.h>
-#include <linux/delay.h>
-#include "clk-mtk.h"
+#include "clk-pll.h"
+
+#define MHZ (1000 * 1000)
#define REG_CON0 0
#define REG_CON1 4
@@ -359,8 +362,24 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
return clk;
}
-void mtk_clk_register_plls(struct device_node *node,
- const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
+static void mtk_clk_unregister_pll(struct clk *clk)
+{
+ struct clk_hw *hw;
+ struct mtk_clk_pll *pll;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ pll = to_mtk_clk_pll(hw);
+
+ clk_unregister(clk);
+ kfree(pll);
+}
+
+int mtk_clk_register_plls(struct device_node *node,
+ const struct mtk_pll_data *plls, int num_plls,
+ struct clk_onecell_data *clk_data)
{
void __iomem *base;
int i;
@@ -369,23 +388,82 @@ void mtk_clk_register_plls(struct device_node *node,
base = of_iomap(node, 0);
if (!base) {
pr_err("%s(): ioremap failed\n", __func__);
- return;
+ return -EINVAL;
}
for (i = 0; i < num_plls; i++) {
const struct mtk_pll_data *pll = &plls[i];
+ if (!IS_ERR_OR_NULL(clk_data->clks[pll->id])) {
+ pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+ node, pll->id);
+ continue;
+ }
+
clk = mtk_clk_register_pll(pll, base);
if (IS_ERR(clk)) {
- pr_err("Failed to register clk %s: %ld\n",
- pll->name, PTR_ERR(clk));
- continue;
+ pr_err("Failed to register clk %s: %pe\n", pll->name, clk);
+ goto err;
}
clk_data->clks[pll->id] = clk;
}
+
+ return 0;
+
+err:
+ while (--i >= 0) {
+ const struct mtk_pll_data *pll = &plls[i];
+
+ mtk_clk_unregister_pll(clk_data->clks[pll->id]);
+ clk_data->clks[pll->id] = ERR_PTR(-ENOENT);
+ }
+
+ iounmap(base);
+
+ return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_plls);
+static __iomem void *mtk_clk_pll_get_base(struct clk *clk,
+ const struct mtk_pll_data *data)
+{
+ struct clk_hw *hw = __clk_get_hw(clk);
+ struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+ return pll->base_addr - data->reg;
+}
+
+void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
+ struct clk_onecell_data *clk_data)
+{
+ __iomem void *base = NULL;
+ int i;
+
+ if (!clk_data)
+ return;
+
+ for (i = num_plls; i > 0; i--) {
+ const struct mtk_pll_data *pll = &plls[i - 1];
+
+ if (IS_ERR_OR_NULL(clk_data->clks[pll->id]))
+ continue;
+
+ /*
+ * This is quite ugly but unfortunately the clks don't have
+ * any device tied to them, so there's no place to store the
+ * pointer to the I/O region base address. We have to fetch
+ * it from one of the registered clks.
+ */
+ base = mtk_clk_pll_get_base(clk_data->clks[pll->id], pll);
+
+ mtk_clk_unregister_pll(clk_data->clks[pll->id]);
+ clk_data->clks[pll->id] = ERR_PTR(-ENOENT);
+ }
+
+ iounmap(base);
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_plls);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
new file mode 100644
index 000000000000..bf06e44caef9
--- /dev/null
+++ b/drivers/clk/mediatek/clk-pll.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ */
+
+#ifndef __DRV_CLK_MTK_PLL_H
+#define __DRV_CLK_MTK_PLL_H
+
+#include <linux/types.h>
+
+struct clk_ops;
+struct clk_onecell_data;
+struct device_node;
+
+struct mtk_pll_div_table {
+ u32 div;
+ unsigned long freq;
+};
+
+#define HAVE_RST_BAR BIT(0)
+#define PLL_AO BIT(1)
+
+struct mtk_pll_data {
+ int id;
+ const char *name;
+ u32 reg;
+ u32 pwr_reg;
+ u32 en_mask;
+ u32 pd_reg;
+ u32 tuner_reg;
+ u32 tuner_en_reg;
+ u8 tuner_en_bit;
+ int pd_shift;
+ unsigned int flags;
+ const struct clk_ops *ops;
+ u32 rst_bar_mask;
+ unsigned long fmin;
+ unsigned long fmax;
+ int pcwbits;
+ int pcwibits;
+ u32 pcw_reg;
+ int pcw_shift;
+ u32 pcw_chg_reg;
+ const struct mtk_pll_div_table *div_table;
+ const char *parent_name;
+ u32 en_reg;
+ u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
+};
+
+int mtk_clk_register_plls(struct device_node *node,
+ const struct mtk_pll_data *plls, int num_plls,
+ struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
+ struct clk_onecell_data *clk_data);
+
+#endif /* __DRV_CLK_MTK_PLL_H */
diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c
index ffe464ce7ff8..bcec4b89f449 100644
--- a/drivers/clk/mediatek/reset.c
+++ b/drivers/clk/mediatek/reset.c
@@ -100,8 +100,7 @@ static void mtk_register_reset_controller_common(struct device_node *np,
regmap = device_node_to_regmap(np);
if (IS_ERR(regmap)) {
- pr_err("Cannot find regmap for %pOF: %ld\n", np,
- PTR_ERR(regmap));
+ pr_err("Cannot find regmap for %pOF: %pe\n", np, regmap);
return;
}