[PATCH v2 6/9] clk: renesas: rzg2l: Add support for RZ/G3L DSI mux
Biju <[email protected]>
| Newsgroups | org.kernel.vger.linux-renesas-soc,org.kernel.vger.linux-clk,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Biju Das <[email protected]> Add support for RZ/G3L DSI mux that supports 2 duty cycles. Signed-off-by: Biju Das <[email protected]> --- v1->v2: * Dropped rzg3l_cpg_dsi_smux_get_duty_cycle(). * Updated Mux flags with CLK_DUTY_CYCLE_PARENT and CLK_SET_RATE_NO_REPARENT * Determine rate now forward to clk_mux_ops.determine_rate(). * Dropped the duty cycle macros. * Dropped struct rzg3l_dsi_mux_clk and to_plldsi_clk_mux. --- drivers/clk/renesas/rzg2l-cpg.c | 84 +++++++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.h | 10 ++++ 2 files changed, 94 insertions(+) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index d3d4e618466c..33cfea1b798a 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1493,6 +1493,87 @@ static const struct clk_ops rzg3l_cpg_pll_ops = { .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate, }; +static u8 rzg3l_cpg_dsi_smux_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int rzg3l_cpg_dsi_smux_set_parent(struct clk_hw *hw, u8 index) +{ + return clk_mux_ops.set_parent(hw, index); +} + +static int rzg3l_cpg_dsi_smux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return clk_mux_ops.determine_rate(hw, req); +} + +static int rzg3l_cpg_dsi_smux_set_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + struct clk_hw *parent_hw; + u8 parent_idx; + + /* + * Select parent based on requested duty cycle: + * - If duty > 50% (num/den > 1/2), select LVDS path (parent 0) + * - Otherwise, select DSI/RGB path (parent 1) + */ + if (duty->num * 2 > duty->den) + parent_idx = 0; + else + parent_idx = 1; + + if (parent_idx >= clk_hw_get_num_parents(hw)) + return -EINVAL; + + parent_hw = clk_hw_get_parent_by_index(hw, parent_idx); + if (!parent_hw) + return -EINVAL; + + return clk_hw_set_parent(hw, parent_hw); +} + +static const struct clk_ops rzg3l_cpg_dsi_smux_ops = { + .determine_rate = rzg3l_cpg_dsi_smux_determine_rate, + .get_parent = rzg3l_cpg_dsi_smux_get_parent, + .set_parent = rzg3l_cpg_dsi_smux_set_parent, + .set_duty_cycle = rzg3l_cpg_dsi_smux_set_duty_cycle, +}; + +static struct clk * __init +rzg3l_cpg_dsi_mux_clk_register(const struct cpg_core_clk *core, + struct rzg2l_cpg_priv *priv) +{ + struct clk_mux *mux_data; + struct clk_init_data init; + int ret; + + mux_data = devm_kzalloc(priv->dev, sizeof(*mux_data), GFP_KERNEL); + if (!mux_data) + return ERR_PTR(-ENOMEM); + + init.name = core->name; + init.ops = &rzg3l_cpg_dsi_smux_ops; + init.flags = core->core_flags | CLK_SET_RATE_PARENT; + init.parent_names = core->parent_names; + init.num_parents = core->num_parents; + + mux_data->reg = priv->base + GET_REG_OFFSET(core->conf); + mux_data->shift = GET_SHIFT(core->conf); + mux_data->mask = clk_div_mask(GET_WIDTH(core->conf)); + mux_data->flags = core->mux_flags; + mux_data->lock = &priv->rmw_lock; + mux_data->hw.init = &init; + + ret = devm_clk_hw_register(priv->dev, &mux_data->hw); + if (ret) + return ERR_PTR(ret); + + return mux_data->hw.clk; +} + static inline bool rzg3l_dsi_compute_pll_parameters(struct rzg3l_plldsi_parameters *pars, struct rzg3l_plldsi_parameters *p, @@ -1805,6 +1886,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, case CLK_TYPE_G3L_PLLDSI: clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3l_cpg_plldsi_ops); break; + case CLK_TYPE_G3L_DSI_MUX: + clk = rzg3l_cpg_dsi_mux_clk_register(core, priv); + break; default: goto fail; } diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 22cca4795301..1591fce2a329 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -151,6 +151,9 @@ enum clk_types { /* Clock for G3L LVDS divider */ CLK_TYPE_G3L_LVDS_DIV, + + /* Clock for G3L DSI clock source selector */ + CLK_TYPE_G3L_DSI_MUX, }; #define DEF_TYPE(_name, _id, _type...) \ @@ -204,6 +207,13 @@ enum clk_types { .parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names), \ .mux_flags = CLK_MUX_READ_ONLY) +#define DEF_G3L_SEL_DSI_MUX(_name, _id, _conf, _parent_names) \ + DEF_TYPE(_name, _id, CLK_TYPE_G3L_DSI_MUX, .conf = _conf, \ + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .core_flags = CLK_SET_RATE_PARENT | CLK_DUTY_CYCLE_PARENT | \ + CLK_SET_RATE_NO_REPARENT, \ + .mux_flags = CLK_MUX_HIWORD_MASK) #define DEF_SD_MUX(_name, _id, _conf, _sconf, _parent_names, _mtable, _clk_flags, _notifier) \ DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \ .parent_names = _parent_names, \ -- 2.43.0