Re: [PATCH 5/5] clk: vc5: optionally configure the output drive mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jul 2, 2020 at 5:40 PM Luca Ceresoli <luca@xxxxxxxxxxxxxxxx> wrote:
>
> The Versaclock chips can drive the output pins in several modes: LVDS,
> CMOS, LVPECL etc. Allow configuring the output mode from device tree.
>
> The configuration is optional. If not specified, the mode will not be
> configured and the drive mode will be the chip default.
>
> Signed-off-by: Luca Ceresoli <luca@xxxxxxxxxxxxxxxx>

This might be duplicating what's been applied to linux-next already.

https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/drivers/clk/clk-versaclock5.c?h=next-20200706&id=260249f929e81d3d5764117fdd6b9e43eb8fb1d5


> ---
>  drivers/clk/clk-versaclock5.c | 71 +++++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
>
> diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
> index 60c7cf9acde3..eec57286fae0 100644
> --- a/drivers/clk/clk-versaclock5.c
> +++ b/drivers/clk/clk-versaclock5.c
> @@ -89,6 +89,8 @@
>
>  /* Clock control register for clock 1,2 */
>  #define VC5_CLK_OUTPUT_CFG(idx, n)     (0x60 + ((idx) * 0x2) + (n))
> +#define VC5_CLK_OUTPUT_CFG0_MODE_SHIFT 5
> +#define VC5_CLK_OUTPUT_CFG0_MODE_MASK  GENMASK(7, 5)
>  #define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF  BIT(0)
>
>  #define VC5_CLK_OE_SHDN                                0x68
> @@ -117,6 +119,23 @@
>  /* chip has PFD requency doubler */
>  #define VC5_HAS_PFD_FREQ_DBL   BIT(1)
>
> +/*
> + * Output modes. Values for VC5_CLK_OUTPUT_CFG(idx,0) bits [7:5].
> + * IDT_VC5_OUT_UNKNOWN = keep the hardware default.
> + */
> +enum vc5_out_mode {
> +       IDT_VC5_OUT_MODE_LVPECL   = 0,
> +       IDT_VC5_OUT_MODE_CMOS     = 1,
> +       IDT_VC5_OUT_MODE_HCSL33   = 2,
> +       IDT_VC5_OUT_MODE_LVDS     = 3,
> +       IDT_VC5_OUT_MODE_CMOS2    = 4,
> +       IDT_VC5_OUT_MODE_CMOSD    = 5,
> +       IDT_VC5_OUT_MODE_HCSL25   = 6,
> +
> +       IDT_VC5_OUT_NUM_MODES,
> +       IDT_VC5_OUT_MODE_UNKNOWN  = 99,
> +};
> +
>  /* Supported IDT VC5 models. */
>  enum vc5_model {
>         IDT_VC5_5P49V5923,
> @@ -149,6 +168,7 @@ struct vc5_out_data {
>         struct clk_hw           hw;
>         struct vc5_driver_data  *vc5;
>         unsigned int            num;
> +       enum vc5_out_mode       mode:8;
>  };
>
>  struct vc5_driver_data {
> @@ -593,6 +613,13 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
>                         return ret;
>         }
>
> +       /* Set output drive mode */
> +       if (hwdata->mode != IDT_VC5_OUT_MODE_UNKNOWN)
> +               regmap_update_bits(vc5->regmap,
> +                                  VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
> +                                  VC5_CLK_OUTPUT_CFG0_MODE_MASK,
> +                                  (hwdata->mode << VC5_CLK_OUTPUT_CFG0_MODE_SHIFT));
> +
>         /* Enable the clock buffer */
>         regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
>                            VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
> @@ -696,6 +723,46 @@ static int vc5_map_index_to_output(const enum vc5_model model,
>         }
>  }
>
> +static int vc5_parse_dt(struct vc5_driver_data *vc5)
> +{
> +       struct device *dev = &vc5->client->dev;
> +       struct device_node *np = dev->of_node;
> +       struct device_node *child;
> +       u32 val;
> +       int n;
> +
> +       for (n = 1; n < vc5->chip_info->clk_out_cnt; n++)
> +               vc5->clk_out[n].mode = IDT_VC5_OUT_MODE_UNKNOWN;
> +
> +       for_each_child_of_node(np, child) {
> +               if (of_property_read_u32(child, "reg", &n)) {
> +                       dev_err(dev, "%pOF: missing reg property\n", child);
> +                       break;
> +               }
> +
> +               if (n == 0 || n >= vc5->chip_info->clk_out_cnt) {
> +                       dev_err(dev, "%pOF: invalid reg %d\n", child, n);
> +                       break;
> +               }
> +
> +               if (!of_property_read_u32(child, "idt,drive-mode", &val)) {
> +                       if (val >= IDT_VC5_OUT_NUM_MODES) {
> +                               dev_err(dev, "%pOF: invalid idt,drive-mode %u\n",
> +                                       child, val);
> +                               break;
> +                       }
> +                       vc5->clk_out[n].mode = val;
> +               }
> +       }
> +
> +       if (child) {
> +               of_node_put(child);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
>  static const struct of_device_id clk_vc5_of_match[];
>
>  static int vc5_probe(struct i2c_client *client,
> @@ -723,6 +790,10 @@ static int vc5_probe(struct i2c_client *client,
>         if (PTR_ERR(vc5->pin_clkin) == -EPROBE_DEFER)
>                 return -EPROBE_DEFER;
>
> +       ret = vc5_parse_dt(vc5);
> +       if (ret)
> +               return ret;
> +
>         vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config);
>         if (IS_ERR(vc5->regmap)) {
>                 dev_err(&client->dev, "failed to allocate register map\n");
> --
> 2.27.0
>



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux