Re: [PATCH v11 2/7] clk: meson: add vclk driver

2024-03-29 Thread Neil Armstrong

On 29/03/2024 13:33, Jerome Brunet wrote:


On Mon 25 Mar 2024 at 12:09, Neil Armstrong  wrote:


The VCLK and VCLK_DIV clocks have supplementary bits.

The VCLK gate has a "SOFT RESET" bit to toggle after the whole
VCLK sub-tree rate has been set, this is implemented in
the gate enable callback.

The VCLK_DIV clocks as enable and reset bits used to disable
and reset the divider, associated with CLK_SET_RATE_GATE it ensures
the rate is set while the divider is disabled and in reset mode.

The VCLK_DIV enable bit isn't implemented as a gate since it's part
of the divider logic and vendor does this exact sequence to ensure
the divider is correctly set.


checkpatch reports a few easy CHECKs and one WARNING.
Could you please fix these ?

Other than that, It looks OK.


Ack
thx

Neil





Signed-off-by: Neil Armstrong 
---
  drivers/clk/meson/Kconfig  |   4 ++
  drivers/clk/meson/Makefile |   1 +
  drivers/clk/meson/vclk.c   | 141 +
  drivers/clk/meson/vclk.h   |  51 
  4 files changed, 197 insertions(+)

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 29ffd14d267b..8a9823789fa3 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -30,6 +30,10 @@ config COMMON_CLK_MESON_VID_PLL_DIV
tristate
select COMMON_CLK_MESON_REGMAP
  
+config COMMON_CLK_MESON_VCLK

+   tristate
+   select COMMON_CLK_MESON_REGMAP
+
  config COMMON_CLK_MESON_CLKC_UTILS
tristate
  
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile

index 9ee4b954c896..9ba43fe7a07a 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
  obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
  obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
  obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
+obj-$(CONFIG_COMMON_CLK_MESON_VCLK) += vclk.o
  
  # Amlogic Clock controllers
  
diff --git a/drivers/clk/meson/vclk.c b/drivers/clk/meson/vclk.c

new file mode 100644
index ..3ea813a0a995
--- /dev/null
+++ b/drivers/clk/meson/vclk.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 Neil Armstrong 
+ */
+
+#include 
+#include "vclk.h"
+
+/* The VCLK gate has a supplementary reset bit to pulse after ungating */
+
+static inline struct meson_vclk_gate_data *
+clk_get_meson_vclk_gate_data(struct clk_regmap *clk)
+{
+   return (struct meson_vclk_gate_data *)clk->data;
+}
+
+static int meson_vclk_gate_enable(struct clk_hw *hw)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
+
+   meson_parm_write(clk->map, >enable, 1);
+
+   /* Do a reset pulse */
+   meson_parm_write(clk->map, >reset, 1);
+   meson_parm_write(clk->map, >reset, 0);
+
+   return 0;
+}
+
+static void meson_vclk_gate_disable(struct clk_hw *hw)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
+
+   meson_parm_write(clk->map, >enable, 0);
+}
+
+static int meson_vclk_gate_is_enabled(struct clk_hw *hw)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
+
+   return meson_parm_read(clk->map, >enable);
+}
+
+const struct clk_ops meson_vclk_gate_ops = {
+   .enable = meson_vclk_gate_enable,
+   .disable = meson_vclk_gate_disable,
+   .is_enabled = meson_vclk_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(meson_vclk_gate_ops);
+
+/* The VCLK Divider has supplementary reset & enable bits */
+
+static inline struct meson_vclk_div_data *
+clk_get_meson_vclk_div_data(struct clk_regmap *clk)
+{
+   return (struct meson_vclk_div_data *)clk->data;
+}
+
+static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
+unsigned long prate)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
+
+   return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, 
>div),
+  vclk->table, vclk->flags, vclk->div.width);
+}
+
+static int meson_vclk_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
+
+   return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
+ vclk->flags);
+}
+
+static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+   unsigned long parent_rate)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_div_data *vclk = 

Re: [PATCH v11 2/7] clk: meson: add vclk driver

2024-03-29 Thread Jerome Brunet


On Mon 25 Mar 2024 at 12:09, Neil Armstrong  wrote:

> The VCLK and VCLK_DIV clocks have supplementary bits.
>
> The VCLK gate has a "SOFT RESET" bit to toggle after the whole
> VCLK sub-tree rate has been set, this is implemented in
> the gate enable callback.
>
> The VCLK_DIV clocks as enable and reset bits used to disable
> and reset the divider, associated with CLK_SET_RATE_GATE it ensures
> the rate is set while the divider is disabled and in reset mode.
>
> The VCLK_DIV enable bit isn't implemented as a gate since it's part
> of the divider logic and vendor does this exact sequence to ensure
> the divider is correctly set.

checkpatch reports a few easy CHECKs and one WARNING.
Could you please fix these ?

Other than that, It looks OK.

>
> Signed-off-by: Neil Armstrong 
> ---
>  drivers/clk/meson/Kconfig  |   4 ++
>  drivers/clk/meson/Makefile |   1 +
>  drivers/clk/meson/vclk.c   | 141 
> +
>  drivers/clk/meson/vclk.h   |  51 
>  4 files changed, 197 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 29ffd14d267b..8a9823789fa3 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -30,6 +30,10 @@ config COMMON_CLK_MESON_VID_PLL_DIV
>   tristate
>   select COMMON_CLK_MESON_REGMAP
>  
> +config COMMON_CLK_MESON_VCLK
> + tristate
> + select COMMON_CLK_MESON_REGMAP
> +
>  config COMMON_CLK_MESON_CLKC_UTILS
>   tristate
>  
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 9ee4b954c896..9ba43fe7a07a 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
>  obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
>  obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
>  obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
> +obj-$(CONFIG_COMMON_CLK_MESON_VCLK) += vclk.o
>  
>  # Amlogic Clock controllers
>  
> diff --git a/drivers/clk/meson/vclk.c b/drivers/clk/meson/vclk.c
> new file mode 100644
> index ..3ea813a0a995
> --- /dev/null
> +++ b/drivers/clk/meson/vclk.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2024 Neil Armstrong 
> + */
> +
> +#include 
> +#include "vclk.h"
> +
> +/* The VCLK gate has a supplementary reset bit to pulse after ungating */
> +
> +static inline struct meson_vclk_gate_data *
> +clk_get_meson_vclk_gate_data(struct clk_regmap *clk)
> +{
> + return (struct meson_vclk_gate_data *)clk->data;
> +}
> +
> +static int meson_vclk_gate_enable(struct clk_hw *hw)
> +{
> + struct clk_regmap *clk = to_clk_regmap(hw);
> + struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
> +
> + meson_parm_write(clk->map, >enable, 1);
> +
> + /* Do a reset pulse */
> + meson_parm_write(clk->map, >reset, 1);
> + meson_parm_write(clk->map, >reset, 0);
> +
> + return 0;
> +}
> +
> +static void meson_vclk_gate_disable(struct clk_hw *hw)
> +{
> + struct clk_regmap *clk = to_clk_regmap(hw);
> + struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
> +
> + meson_parm_write(clk->map, >enable, 0);
> +}
> +
> +static int meson_vclk_gate_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_regmap *clk = to_clk_regmap(hw);
> + struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
> +
> + return meson_parm_read(clk->map, >enable);
> +}
> +
> +const struct clk_ops meson_vclk_gate_ops = {
> + .enable = meson_vclk_gate_enable,
> + .disable = meson_vclk_gate_disable,
> + .is_enabled = meson_vclk_gate_is_enabled,
> +};
> +EXPORT_SYMBOL_GPL(meson_vclk_gate_ops);
> +
> +/* The VCLK Divider has supplementary reset & enable bits */
> +
> +static inline struct meson_vclk_div_data *
> +clk_get_meson_vclk_div_data(struct clk_regmap *clk)
> +{
> + return (struct meson_vclk_div_data *)clk->data;
> +}
> +
> +static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
> +  unsigned long prate)
> +{
> + struct clk_regmap *clk = to_clk_regmap(hw);
> + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
> +
> + return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, 
> >div),
> +vclk->table, vclk->flags, vclk->div.width);
> +}
> +
> +static int meson_vclk_div_determine_rate(struct clk_hw *hw,
> +   struct clk_rate_request *req)
> +{
> + struct clk_regmap *clk = to_clk_regmap(hw);
> + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
> +
> + return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
> +   vclk->flags);
> +}
> +
> +static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long 

[PATCH v11 2/7] clk: meson: add vclk driver

2024-03-25 Thread Neil Armstrong
The VCLK and VCLK_DIV clocks have supplementary bits.

The VCLK gate has a "SOFT RESET" bit to toggle after the whole
VCLK sub-tree rate has been set, this is implemented in
the gate enable callback.

The VCLK_DIV clocks as enable and reset bits used to disable
and reset the divider, associated with CLK_SET_RATE_GATE it ensures
the rate is set while the divider is disabled and in reset mode.

The VCLK_DIV enable bit isn't implemented as a gate since it's part
of the divider logic and vendor does this exact sequence to ensure
the divider is correctly set.

Signed-off-by: Neil Armstrong 
---
 drivers/clk/meson/Kconfig  |   4 ++
 drivers/clk/meson/Makefile |   1 +
 drivers/clk/meson/vclk.c   | 141 +
 drivers/clk/meson/vclk.h   |  51 
 4 files changed, 197 insertions(+)

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 29ffd14d267b..8a9823789fa3 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -30,6 +30,10 @@ config COMMON_CLK_MESON_VID_PLL_DIV
tristate
select COMMON_CLK_MESON_REGMAP
 
+config COMMON_CLK_MESON_VCLK
+   tristate
+   select COMMON_CLK_MESON_REGMAP
+
 config COMMON_CLK_MESON_CLKC_UTILS
tristate
 
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 9ee4b954c896..9ba43fe7a07a 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
 obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
 obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
 obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
+obj-$(CONFIG_COMMON_CLK_MESON_VCLK) += vclk.o
 
 # Amlogic Clock controllers
 
diff --git a/drivers/clk/meson/vclk.c b/drivers/clk/meson/vclk.c
new file mode 100644
index ..3ea813a0a995
--- /dev/null
+++ b/drivers/clk/meson/vclk.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 Neil Armstrong 
+ */
+
+#include 
+#include "vclk.h"
+
+/* The VCLK gate has a supplementary reset bit to pulse after ungating */
+
+static inline struct meson_vclk_gate_data *
+clk_get_meson_vclk_gate_data(struct clk_regmap *clk)
+{
+   return (struct meson_vclk_gate_data *)clk->data;
+}
+
+static int meson_vclk_gate_enable(struct clk_hw *hw)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
+
+   meson_parm_write(clk->map, >enable, 1);
+
+   /* Do a reset pulse */
+   meson_parm_write(clk->map, >reset, 1);
+   meson_parm_write(clk->map, >reset, 0);
+
+   return 0;
+}
+
+static void meson_vclk_gate_disable(struct clk_hw *hw)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
+
+   meson_parm_write(clk->map, >enable, 0);
+}
+
+static int meson_vclk_gate_is_enabled(struct clk_hw *hw)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
+
+   return meson_parm_read(clk->map, >enable);
+}
+
+const struct clk_ops meson_vclk_gate_ops = {
+   .enable = meson_vclk_gate_enable,
+   .disable = meson_vclk_gate_disable,
+   .is_enabled = meson_vclk_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(meson_vclk_gate_ops);
+
+/* The VCLK Divider has supplementary reset & enable bits */
+
+static inline struct meson_vclk_div_data *
+clk_get_meson_vclk_div_data(struct clk_regmap *clk)
+{
+   return (struct meson_vclk_div_data *)clk->data;
+}
+
+static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
+unsigned long prate)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
+
+   return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, 
>div),
+  vclk->table, vclk->flags, vclk->div.width);
+}
+
+static int meson_vclk_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
+
+   return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
+ vclk->flags);
+}
+
+static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+   unsigned long parent_rate)
+{
+   struct clk_regmap *clk = to_clk_regmap(hw);
+   struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
+   int ret;
+
+   ret = divider_get_val(rate, parent_rate, vclk->table, vclk->div.width,
+ vclk->flags);
+   if (ret < 0)
+   return ret;
+
+   meson_parm_write(clk->map, >div, ret);
+