1 // SPDX-License-Identifier: GPL-2.0
5 #define pr_fmt(fmt) "imx:clk-gpr-mux: " fmt
7 #include <linux/module.h>
9 #include <linux/clk-provider.h>
10 #include <linux/errno.h>
11 #include <linux/export.h>
13 #include <linux/slab.h>
14 #include <linux/regmap.h>
15 #include <linux/mfd/syscon.h>
21 struct regmap
*regmap
;
27 static struct imx_clk_gpr
*to_imx_clk_gpr(struct clk_hw
*hw
)
29 return container_of(hw
, struct imx_clk_gpr
, hw
);
32 static u8
imx_clk_gpr_mux_get_parent(struct clk_hw
*hw
)
34 struct imx_clk_gpr
*priv
= to_imx_clk_gpr(hw
);
38 ret
= regmap_read(priv
->regmap
, priv
->reg
, &val
);
44 ret
= clk_mux_val_to_index(hw
, priv
->mux_table
, 0, val
);
51 pr_err("%s: failed to get parent (%pe)\n",
52 clk_hw_get_name(hw
), ERR_PTR(ret
));
54 /* return some realistic non negative value. Potentially we could
55 * give index to some dummy error parent.
60 static int imx_clk_gpr_mux_set_parent(struct clk_hw
*hw
, u8 index
)
62 struct imx_clk_gpr
*priv
= to_imx_clk_gpr(hw
);
63 unsigned int val
= clk_mux_index_to_val(priv
->mux_table
, 0, index
);
65 return regmap_update_bits(priv
->regmap
, priv
->reg
, priv
->mask
, val
);
68 static const struct clk_ops imx_clk_gpr_mux_ops
= {
69 .get_parent
= imx_clk_gpr_mux_get_parent
,
70 .set_parent
= imx_clk_gpr_mux_set_parent
,
71 .determine_rate
= __clk_mux_determine_rate
,
74 struct clk_hw
*imx_clk_gpr_mux(const char *name
, const char *compatible
,
75 u32 reg
, const char **parent_names
,
76 u8 num_parents
, const u32
*mux_table
, u32 mask
)
78 struct clk_init_data init
= { };
79 struct imx_clk_gpr
*priv
;
80 struct regmap
*regmap
;
84 regmap
= syscon_regmap_lookup_by_compatible(compatible
);
86 pr_err("failed to find %s regmap\n", compatible
);
87 return ERR_CAST(regmap
);
90 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
92 return ERR_PTR(-ENOMEM
);
95 init
.ops
= &imx_clk_gpr_mux_ops
;
96 init
.parent_names
= parent_names
;
97 init
.num_parents
= num_parents
;
98 init
.flags
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
;
100 priv
->hw
.init
= &init
;
101 priv
->regmap
= regmap
;
102 priv
->mux_table
= mux_table
;
107 ret
= clk_hw_register(NULL
, &priv
->hw
);