[media] mt9p031: Add support for PLL bypass

When the input clock frequency is out of bounds for the PLL, bypass the
PLL and just divide the input clock to achieve the requested output
frequency.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index a271662..fec76d3 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -78,6 +78,9 @@
 #define	MT9P031_PLL_CONFIG_1				0x11
 #define	MT9P031_PLL_CONFIG_2				0x12
 #define MT9P031_PIXEL_CLOCK_CONTROL			0x0a
+#define		MT9P031_PIXEL_CLOCK_INVERT		(1 << 15)
+#define		MT9P031_PIXEL_CLOCK_SHIFT(n)		((n) << 8)
+#define		MT9P031_PIXEL_CLOCK_DIVIDE(n)		((n) << 0)
 #define MT9P031_FRAME_RESTART				0x0b
 #define MT9P031_SHUTTER_DELAY				0x0c
 #define MT9P031_RST					0x0d
@@ -130,6 +133,8 @@
 
 	enum mt9p031_model model;
 	struct aptina_pll pll;
+	unsigned int clk_div;
+	bool use_pll;
 	int reset;
 
 	struct v4l2_ctrl_handler ctrls;
@@ -198,6 +203,11 @@
 	if (ret < 0)
 		return ret;
 
+	ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL,
+			    MT9P031_PIXEL_CLOCK_DIVIDE(mt9p031->clk_div));
+	if (ret < 0)
+		return ret;
+
 	return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
 					  0);
 }
@@ -229,8 +239,24 @@
 
 	clk_set_rate(mt9p031->clk, pdata->ext_freq);
 
+	/* If the external clock frequency is out of bounds for the PLL use the
+	 * pixel clock divider only and disable the PLL.
+	 */
+	if (pdata->ext_freq > limits.ext_clock_max) {
+		unsigned int div;
+
+		div = DIV_ROUND_UP(pdata->ext_freq, pdata->target_freq);
+		div = roundup_pow_of_two(div) / 2;
+
+		mt9p031->clk_div = max_t(unsigned int, div, 64);
+		mt9p031->use_pll = false;
+
+		return 0;
+	}
+
 	mt9p031->pll.ext_clock = pdata->ext_freq;
 	mt9p031->pll.pix_clock = pdata->target_freq;
+	mt9p031->use_pll = true;
 
 	return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
 }
@@ -240,6 +266,9 @@
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
 	int ret;
 
+	if (!mt9p031->use_pll)
+		return 0;
+
 	ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
 			    MT9P031_PLL_CONTROL_PWRON);
 	if (ret < 0)
@@ -265,6 +294,9 @@
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
 
+	if (!mt9p031->use_pll)
+		return 0;
+
 	return mt9p031_write(client, MT9P031_PLL_CONTROL,
 			     MT9P031_PLL_CONTROL_PWROFF);
 }