xref: /linux/drivers/clk/qcom/clk-regmap-phy-mux.c (revision 2b109eccd80b660e58d4523e8b80ce11bc3e532e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022, Linaro Ltd.
4  */
5 
6 #include <linux/clk-provider.h>
7 #include <linux/bitfield.h>
8 #include <linux/regmap.h>
9 #include <linux/export.h>
10 
11 #include "clk-regmap.h"
12 #include "clk-regmap-phy-mux.h"
13 
14 #define PHY_MUX_MASK		GENMASK(1, 0)
15 #define PHY_MUX_PHY_SRC		0
16 #define PHY_MUX_REF_SRC		2
17 
18 #define XO_RATE			19200000UL
19 
20 static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_regmap *clkr)
21 {
22 	return container_of(clkr, struct clk_regmap_phy_mux, clkr);
23 }
24 
25 static unsigned long phy_mux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
26 {
27 	struct clk_regmap *clkr = to_clk_regmap(hw);
28 	struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
29 	u32 val;
30 
31 	regmap_read(clkr->regmap, phy_mux->reg, &val);
32 
33 	switch (FIELD_GET(PHY_MUX_MASK, val)) {
34 	case PHY_MUX_PHY_SRC:
35 		return ULONG_MAX;
36 	case PHY_MUX_REF_SRC:
37 		return XO_RATE;
38 	default:
39 		return 0;
40 	}
41 }
42 
43 static int phy_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
44 {
45 	if (req->rate == XO_RATE || req->rate == ULONG_MAX)
46 		return 0;
47 
48 	return -EINVAL;
49 }
50 
51 static int phy_mux_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
52 {
53 	struct clk_regmap *clkr = to_clk_regmap(hw);
54 	struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
55 	u32 val;
56 
57 	switch (rate) {
58 	case XO_RATE:
59 		val = PHY_MUX_REF_SRC;
60 		break;
61 	case ULONG_MAX:
62 		val = PHY_MUX_PHY_SRC;
63 		break;
64 	default:
65 		return -EINVAL;
66 	}
67 
68 	regmap_update_bits(clkr->regmap, phy_mux->reg,
69 			   PHY_MUX_MASK,
70 			   FIELD_PREP(PHY_MUX_MASK, val));
71 
72 	return 0;
73 }
74 
75 const struct clk_ops clk_regmap_phy_mux_ops = {
76 	.recalc_rate = phy_mux_recalc_rate,
77 	.determine_rate = phy_mux_determine_rate,
78 	.set_rate = phy_mux_set_rate,
79 };
80 EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
81