media: ccs: Dual PLL support
authorSakari Ailus <sakari.ailus@linux.intel.com>
Wed, 16 Sep 2020 09:36:32 +0000 (11:36 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Mon, 7 Dec 2020 15:05:04 +0000 (16:05 +0100)
Add support for sensors that either require dual PLL or support single or
dual PLL but use dual PLL as default.

Use sensor default configuration for sensors that support both modes.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/i2c/ccs-pll.c
drivers/media/i2c/ccs/ccs-core.c

index 91b578a05a98c07bed0603f758c5f12f6fbcfe07..7df7b96e78e6fd68e2c59955f477f65a30198385 100644 (file)
@@ -331,7 +331,10 @@ __ccs_pll_calculate_vt_tree(struct device *dev,
                        continue;
                }
 
-               if (pix_div * sys_div <= best_div) {
+               dev_dbg(dev, "sys/pix/best_pix: %u,%u,%u\n", sys_div, pix_div,
+                       best_pix_div);
+
+               if (pix_div * sys_div <= best_pix_div) {
                        best_pix_div = pix_div;
                        best_div = pix_div * sys_div;
                }
@@ -804,7 +807,9 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
                if (rval)
                        continue;
 
-               rval = check_fr_bounds(dev, lim, pll, PLL_VT);
+               rval = check_fr_bounds(dev, lim, pll,
+                                      pll->flags & CCS_PLL_FLAG_DUAL_PLL ?
+                                      PLL_OP : PLL_VT);
                if (rval)
                        continue;
 
index fa878ecf55a7b6d237c02f37ba40d2dcae811fa7..580166b84878aa9edca4fc6625866f9b636c841a 100644 (file)
@@ -395,7 +395,23 @@ static int ccs_pll_configure(struct ccs_sensor *sensor)
        if (rval < 0)
                return rval;
 
-       return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op_bk.sys_clk_div);
+       rval = ccs_write(sensor, OP_SYS_CLK_DIV, pll->op_bk.sys_clk_div);
+       if (rval < 0)
+               return rval;
+
+       if (!(pll->flags & CCS_PLL_FLAG_DUAL_PLL))
+               return 0;
+
+       rval = ccs_write(sensor, PLL_MODE, CCS_PLL_MODE_DUAL);
+       if (rval < 0)
+               return rval;
+
+       rval = ccs_write(sensor, OP_PRE_PLL_CLK_DIV,
+                        pll->op_fr.pre_pll_clk_div);
+       if (rval < 0)
+               return rval;
+
+       return ccs_write(sensor, OP_PLL_MULTIPLIER, pll->op_fr.pll_multiplier);
 }
 
 static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll)
@@ -412,6 +428,16 @@ static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll)
                        .min_pll_op_clk_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ),
                        .max_pll_op_clk_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ),
                },
+               .op_fr = {
+                       .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_OP_PRE_PLL_CLK_DIV),
+                       .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_OP_PRE_PLL_CLK_DIV),
+                       .min_pll_ip_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PLL_IP_CLK_FREQ_MHZ),
+                       .max_pll_ip_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PLL_IP_CLK_FREQ_MHZ),
+                       .min_pll_multiplier = CCS_LIM(sensor, MIN_OP_PLL_MULTIPLIER),
+                       .max_pll_multiplier = CCS_LIM(sensor, MAX_OP_PLL_MULTIPLIER),
+                       .min_pll_op_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PLL_OP_CLK_FREQ_MHZ),
+                       .max_pll_op_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PLL_OP_CLK_FREQ_MHZ),
+               },
                .op_bk = {
                         .min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV),
                         .max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV),
@@ -3231,6 +3257,23 @@ static int ccs_probe(struct i2c_client *client)
            CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING)
                sensor->pll.flags |= CCS_PLL_FLAG_FIFO_DERATING |
                                     CCS_PLL_FLAG_FIFO_OVERRATING;
+       if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) &
+           CCS_CLOCK_TREE_PLL_CAPABILITY_DUAL_PLL) {
+               if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) &
+                   CCS_CLOCK_TREE_PLL_CAPABILITY_SINGLE_PLL) {
+                       u32 v;
+
+                       /* Use sensor default in PLL mode selection */
+                       rval = ccs_read(sensor, PLL_MODE, &v);
+                       if (rval)
+                               goto out_cleanup;
+
+                       if (v == CCS_PLL_MODE_DUAL)
+                               sensor->pll.flags |= CCS_PLL_FLAG_DUAL_PLL;
+               } else {
+                       sensor->pll.flags |= CCS_PLL_FLAG_DUAL_PLL;
+               }
+       }
        sensor->pll.op_bits_per_lane = CCS_LIM(sensor, OP_BITS_PER_LANE);
        sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk;
        sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN);