Hi Jan,

On Thu, Sep 05, 2019 at 11:56:01AM +0100, Jan Kotas wrote:
> This patch adds support for CSI2RX v2.1 version of the controller.
> 
> Signed-off-by: Jan Kotas <j...@cadence.com>
> ---
>  drivers/media/platform/cadence/cdns-csi2rx.c | 139 
> ++++++++++++++++++++++-----
>  1 file changed, 116 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c 
> b/drivers/media/platform/cadence/cdns-csi2rx.c
> index 97ec09e72..aa1d46111 100644
> --- a/drivers/media/platform/cadence/cdns-csi2rx.c
> +++ b/drivers/media/platform/cadence/cdns-csi2rx.c
> @@ -1,6 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0+
>  /*
> - * Driver for Cadence MIPI-CSI2 RX Controller v1.3
> + * Driver for Cadence MIPI-CSI2 RX Controller
>   *
>   * Copyright (C) 2017-2019 Cadence Design Systems Inc.
>   */
> @@ -26,6 +26,9 @@
>  #define CSI2RX_SOFT_RESET_PROTOCOL                   BIT(1)
>  #define CSI2RX_SOFT_RESET_FRONT                              BIT(0)
>  
> +#define CSI2RX_V2_CORE_CTRL_REG                      0x004
> +#define CSI2RX_V2_CORE_CTRL_START                    BIT(0)
> +
>  #define CSI2RX_STATIC_CFG_REG                        0x008
>  #define CSI2RX_STATIC_CFG_DLANE_MAP(llane, plane)    ((plane) << (16 + 
> (llane) * 4))
>  #define CSI2RX_STATIC_CFG_LANES_MASK                 GENMASK(11, 8)
> @@ -54,6 +57,15 @@ enum csi2rx_pads {
>       CSI2RX_PAD_MAX,
>  };
>  
> +struct csi2rx_priv;
> +
> +/* CSI2RX Variant Operations */
> +struct csi2rx_vops {
> +     void (*get_dev_cfg)(struct csi2rx_priv *csi2rx);
> +     void (*reset)(struct csi2rx_priv *csi2rx);
> +     void (*map_static)(struct csi2rx_priv *csi2rx);
> +};
> +
>  struct csi2rx_priv {
>       struct device                   *dev;
>       unsigned int                    count;
> @@ -69,6 +81,7 @@ struct csi2rx_priv {
>       struct clk                      *p_clk;
>       struct clk                      *pixel_clk[CSI2RX_STREAMS_MAX];
>       struct phy                      *dphy;
> +     struct csi2rx_vops              *vops;

const?

>  
>       u8                              lanes[CSI2RX_LANES_MAX];
>       u8                              num_lanes;
> @@ -92,6 +105,32 @@ struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct 
> v4l2_subdev *subdev)
>       return container_of(subdev, struct csi2rx_priv, subdev);
>  }
>  
> +static void csi2rx_get_dev_cfg(struct csi2rx_priv *csi2rx)
> +{
> +     u32 dev_cfg;
> +
> +     clk_prepare_enable(csi2rx->p_clk);
> +     dev_cfg = readl(csi2rx->base + CSI2RX_DEVICE_CFG_REG);
> +     clk_disable_unprepare(csi2rx->p_clk);
> +
> +     csi2rx->max_lanes = dev_cfg & 7;
> +     csi2rx->max_streams = (dev_cfg >> 4) & 7;
> +     csi2rx->has_internal_dphy = dev_cfg & BIT(3) ? true : false;

Could you spell out these a little, by adding #defines for the register
bits? Same below.

> +}
> +
> +static void csi2rx_v2_get_dev_cfg(struct csi2rx_priv *csi2rx)
> +{
> +     u32 dev_cfg;
> +
> +     clk_prepare_enable(csi2rx->p_clk);
> +     dev_cfg = readl(csi2rx->base + CSI2RX_DEVICE_CFG_REG);
> +     clk_disable_unprepare(csi2rx->p_clk);
> +
> +     csi2rx->max_lanes = dev_cfg & 0xF;
> +     csi2rx->max_streams = (dev_cfg >> 5) & 0xF;
> +     csi2rx->has_internal_dphy = dev_cfg & BIT(4) ? true : false;
> +}
> +
>  static void csi2rx_reset(struct csi2rx_priv *csi2rx)
>  {
>       writel(CSI2RX_SOFT_RESET_PROTOCOL | CSI2RX_SOFT_RESET_FRONT,
> @@ -102,18 +141,21 @@ static void csi2rx_reset(struct csi2rx_priv *csi2rx)
>       writel(0, csi2rx->base + CSI2RX_SOFT_RESET_REG);
>  }
>  
> -static int csi2rx_start(struct csi2rx_priv *csi2rx)
> +static void csi2rx_v2_reset(struct csi2rx_priv *csi2rx)
> +{
> +     writel(0, csi2rx->base + CSI2RX_V2_CORE_CTRL_REG);
> +
> +     udelay(10);
> +
> +     writel(CSI2RX_V2_CORE_CTRL_START,
> +            csi2rx->base + CSI2RX_V2_CORE_CTRL_REG);
> +}
> +
> +static void csi2rx_map_static(struct csi2rx_priv *csi2rx)
>  {
>       unsigned int i;
>       unsigned long lanes_used = 0;
>       u32 reg;
> -     int ret;
> -
> -     ret = clk_prepare_enable(csi2rx->p_clk);
> -     if (ret)
> -             return ret;
> -
> -     csi2rx_reset(csi2rx);
>  
>       reg = csi2rx->num_lanes << 8;
>       for (i = 0; i < csi2rx->num_lanes; i++) {
> @@ -135,6 +177,32 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx)
>       }
>  
>       writel(reg, csi2rx->base + CSI2RX_STATIC_CFG_REG);
> +}
> +
> +static void csi2rx_v2_map_static(struct csi2rx_priv *csi2rx)
> +{
> +     u32 reg;
> +
> +     reg = csi2rx->num_lanes << 4;
> +     writel(reg, csi2rx->base + CSI2RX_STATIC_CFG_REG);
> +}
> +
> +static int csi2rx_start(struct csi2rx_priv *csi2rx)
> +{
> +     unsigned int i;
> +     int ret;
> +
> +     ret = clk_prepare_enable(csi2rx->p_clk);
> +     if (ret)
> +             return ret;
> +
> +     if (csi2rx->vops) {
> +             if (csi2rx->vops->reset)
> +                     csi2rx->vops->reset(csi2rx);
> +
> +             if (csi2rx->vops->map_static)
> +                     csi2rx->vops->map_static(csi2rx);
> +     }
>  
>       ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true);
>       if (ret)
> @@ -282,7 +350,6 @@ static int csi2rx_get_resources(struct csi2rx_priv 
> *csi2rx,
>  {
>       struct resource *res;
>       unsigned char i;
> -     u32 dev_cfg;
>  
>       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>       csi2rx->base = devm_ioremap_resource(&pdev->dev, res);
> @@ -316,26 +383,25 @@ static int csi2rx_get_resources(struct csi2rx_priv 
> *csi2rx,
>               return -EINVAL;
>       }
>  
> -     clk_prepare_enable(csi2rx->p_clk);
> -     dev_cfg = readl(csi2rx->base + CSI2RX_DEVICE_CFG_REG);
> -     clk_disable_unprepare(csi2rx->p_clk);
> +     if (csi2rx->vops && csi2rx->vops->get_dev_cfg) {
> +             csi2rx->vops->get_dev_cfg(csi2rx);
> +     } else {
> +             dev_err(&pdev->dev, "Couldn't get device configuration\n");
> +             return -EINVAL;
> +     }
>  
> -     csi2rx->max_lanes = dev_cfg & 7;
>       if (csi2rx->max_lanes > CSI2RX_LANES_MAX) {
>               dev_err(&pdev->dev, "Invalid number of lanes: %u\n",
>                       csi2rx->max_lanes);
>               return -EINVAL;
>       }
>  
> -     csi2rx->max_streams = (dev_cfg >> 4) & 7;
>       if (csi2rx->max_streams > CSI2RX_STREAMS_MAX) {
>               dev_err(&pdev->dev, "Invalid number of streams: %u\n",
>                       csi2rx->max_streams);
>               return -EINVAL;
>       }
>  
> -     csi2rx->has_internal_dphy = dev_cfg & BIT(3) ? true : false;
> -
>       /*
>        * FIXME: Once we'll have internal D-PHY support, the check
>        * will need to be removed.
> @@ -426,9 +492,39 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
>       return ret;
>  }
>  
> +static const struct csi2rx_vops csi2rx_vops = {
> +     .get_dev_cfg = csi2rx_get_dev_cfg,
> +     .reset = csi2rx_reset,
> +     .map_static = csi2rx_map_static
> +};
> +
> +static const struct csi2rx_vops csi2rx_v2_vops = {
> +     .get_dev_cfg = csi2rx_v2_get_dev_cfg,
> +     .reset = csi2rx_v2_reset,
> +     .map_static = csi2rx_v2_map_static
> +};
> +
> +static const struct of_device_id csi2rx_of_table[] = {
> +     {
> +             .compatible = "cdns,csi2rx",
> +             .data = &csi2rx_vops
> +     },
> +     {
> +             .compatible = "cdns,csi2rx-1.3",
> +             .data = &csi2rx_vops
> +     },
> +     {
> +             .compatible = "cdns,csi2rx-2.1",
> +             .data = &csi2rx_v2_vops
> +     },
> +     { }
> +};
> +MODULE_DEVICE_TABLE(of, csi2rx_of_table);
> +
>  static int csi2rx_probe(struct platform_device *pdev)
>  {
>       struct csi2rx_priv *csi2rx;
> +     const struct of_device_id *of_id;
>       unsigned int i;
>       int ret;
>  
> @@ -439,6 +535,9 @@ static int csi2rx_probe(struct platform_device *pdev)
>       csi2rx->dev = &pdev->dev;
>       mutex_init(&csi2rx->lock);
>  
> +     of_id = of_match_node(csi2rx_of_table, pdev->dev.of_node);
> +     csi2rx->vops = (struct csi2rx_vops *)of_id->data;

The cast isn't needed, is it?

> +
>       ret = csi2rx_get_resources(csi2rx, pdev);
>       if (ret)
>               goto err_free_priv;
> @@ -493,12 +592,6 @@ static int csi2rx_remove(struct platform_device *pdev)
>       return 0;
>  }
>  
> -static const struct of_device_id csi2rx_of_table[] = {
> -     { .compatible = "cdns,csi2rx" },
> -     { },
> -};
> -MODULE_DEVICE_TABLE(of, csi2rx_of_table);
> -
>  static struct platform_driver csi2rx_driver = {
>       .probe  = csi2rx_probe,
>       .remove = csi2rx_remove,

-- 
Kind regards,

Sakari Ailus

Reply via email to