+/*
+ *
+ * The current best guess of the clock tree, as reverse engineered by several
+ * people on the media mailing list:
+ *
+ * +--------------+
+ * | Ext. Clock |
+ * +------+-------+
+ * |
+ * +------+-------+ - reg 0x3037[3:0] for the pre-divider
+ * | System PLL | - reg 0x3036 for the multiplier
+ * +--+-----------+ - reg 0x3035[7:4] for the system divider
+ * |
+ * | +--------------+
+ * |---+ MIPI Rate | - reg 0x3035[3:0] for the MIPI root divider
+ * | +--------------+
+ * |
+ * +--+-----------+
+ * | PLL Root Div | - (reg 0x3037[4])+1 for the root divider
+ * +--+-----------+
+ * |
+ * +------+-------+
+ * | MIPI Bit Div | - reg 0x3034[3:0]/4 for divider when in MIPI mode, else 1
+ * +--+-----------+
+ * |
+ * | +--------------+
+ * |---+ SCLK | - log2(reg 0x3108[1:0]) for the root divider
+ * | +--------------+
+ * |
+ * +--+-----------+ - reg 0x3035[3:0] for the MIPI root divider
+ * | PCLK | - log2(reg 0x3108[5:4]) for the DVP root divider
+ * +--------------+
+ *
+ * Not all limitations of register values are documented above, see ov5640
+ * datasheet.
+ *
+ * In order for the sensor to operate correctly the ratio of
+ * SCLK:PCLK:MIPI RATE must be 1:2:8 when the scalar in the ISP is not
+ * enabled, and 1:1:4 when it is enabled (MIPI rate doesn't matter in DVP mode).
+ * The ratio of these different clocks is maintained by the constant div values
+ * below, with PCLK div being selected based on if the mode is using the scalar.
+ */
+
+/*
+ * This is supposed to be ranging from 1 to 16, but the value is
+ * always set to either 1 or 2 in the vendor kernels.
+ */
+#define OV5640_SYSDIV_MIN 1
+#define OV5640_SYSDIV_MAX 12
+
+/*
+ * This is supposed to be ranging from 1 to 8, but the value is always
+ * set to 3 in the vendor kernels.
+ */
+#define OV5640_PLL_PREDIV 2
+
+/*
+ *This is supposed to be ranging from 4-252, but must be even when >127
+ */
+#define OV5640_PLL_MULT_MIN 4
+#define OV5640_PLL_MULT_MAX 252
+
+/*
+ * This is supposed to be ranging from 1 to 2, but the value is always
+ * set to 1 in the vendor kernels.
+ */
+#define OV5640_PLL_DVP_ROOT_DIV 1
+#define OV5640_PLL_MIPI_ROOT_DIV 2
+
+/*
+ * This is supposed to be ranging from 1 to 8, but the value is always
+ * set to 2 in the vendor kernels.
+ */
+#define OV5640_SCLK_ROOT_DIV 2
+
+/*
+ * This is equal to the MIPI bit rate divided by 4. Now it is hardcoded to
+ * only work with 8-bit formats, so this value will need to be set in
+ * software if support for 10-bit formats is added. The bit divider is
+ * only active when in MIPI mode (not DVP)
+ */
+#define OV5640_BIT_DIV 2
+
+static unsigned long ov5640_compute_sclk(struct ov5640_dev *sensor,
+ u8 sys_div, u8 pll_prediv,
+ u8 pll_mult, u8 pll_div,
+ u8 sclk_div)
+{
+ unsigned long rate = clk_get_rate(sensor->xclk);
+
+ rate = rate / pll_prediv * pll_mult / sys_div / pll_div;
+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2)
+ rate = rate / OV5640_BIT_DIV;
+
+ return rate / sclk_div;
+}
+
+static unsigned long ov5640_calc_sclk(struct ov5640_dev *sensor,
+ unsigned long rate,
+ u8 *sysdiv, u8 *prediv, u8 pll_rdiv,
+ u8 *mult, u8 *sclk_rdiv)
+{
+ unsigned long best = ~0;
+ u8 best_sysdiv = 1, best_mult = 1;
+ u8 _sysdiv, _pll_mult;
+
+ for (_sysdiv = OV5640_SYSDIV_MIN;
+ _sysdiv <= OV5640_SYSDIV_MAX;
+ _sysdiv++) {
+ for (_pll_mult = OV5640_PLL_MULT_MIN;
+ _pll_mult <= OV5640_PLL_MULT_MAX;
+ _pll_mult++) {
+ unsigned long _rate;
+
+ /*
+ * The PLL multiplier cannot be odd if above
+ * 127.
+ */
+ if (_pll_mult > 127 && (_pll_mult % 2))
+ continue;
+
+ _rate = ov5640_compute_sclk(sensor, _sysdiv,
+ OV5640_PLL_PREDIV,
+ _pll_mult,
+ pll_rdiv,
+ OV5640_SCLK_ROOT_DIV);
+
+ if (abs(rate - _rate) < abs(rate - best)) {
+ best = _rate;
+ best_sysdiv = _sysdiv;
+ best_mult = _pll_mult;
+ }
+
+ if (_rate == rate)
+ goto out;
+ if (_rate > rate)
+ break;
+ }
+ }
+
+out:
+ *sysdiv = best_sysdiv;
+ *prediv = OV5640_PLL_PREDIV;
+ *mult = best_mult;
+ *sclk_rdiv = OV5640_SCLK_ROOT_DIV;
+ return best;
+}
+
+static int ov5640_set_sclk(struct ov5640_dev *sensor,
+ const struct ov5640_mode_info *mode)
+{
+ u8 sysdiv, prediv, mult, pll_rdiv, sclk_rdiv, mipi_div, pclk_div;
+ int ret;
+ unsigned long rate;
+ unsigned char bpp;
+
+ /*
+ * All the formats we support have 2 bytes per pixel, except for JPEG
+ * which is 1 byte per pixel.
+ */
+ bpp = sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8 ? 1 : 2;
+ rate = mode->vtot * mode->htot * bpp;
+ rate *= ov5640_framerates[sensor->current_fr];
+
+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2)
+ rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
+
+ pll_rdiv = (sensor->ep.bus_type == V4L2_MBUS_CSI2) ?
+ OV5640_PLL_MIPI_ROOT_DIV : OV5640_PLL_DVP_ROOT_DIV;
+
+ ov5640_calc_sclk(sensor, rate, &sysdiv, &prediv, pll_rdiv,
+ &mult, &sclk_rdiv);
+
+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2) {
+ mipi_div = (sensor->current_mode->scaler) ? 2 : 1;
+ pclk_div = 1;
+ } else {
+ mipi_div = 1;
+ pclk_div = (sensor->current_mode->scaler) ? 2 : 1;
+ }
+
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
+ 0xff, (sysdiv << 4) | (mipi_div & 0x0f));
+ if (ret)
+ return ret;
+
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
+ 0xff, mult);
+ if (ret)
+ return ret;
+
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
+ 0x1f, prediv | ((pll_rdiv - 1) << 4));
+ if (ret)
+ return ret;
+
+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3F,
+ (ilog2(pclk_div) << 4) |
+ (ilog2(sclk_rdiv / 2) << 2) |
+ ilog2(sclk_rdiv));
+}
+