aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c/mt9p031.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-02-09 15:31:47 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-02-24 11:12:36 -0500
commita970449e40789a0056424668da5b56f57569ea73 (patch)
treeea77264963dd3c5c9ce814d215f9fbefe944c9e8 /drivers/media/i2c/mt9p031.c
parente8e45593c920a05b1f4b9d94738a84039b9b4f22 (diff)
[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>
Diffstat (limited to 'drivers/media/i2c/mt9p031.c')
-rw-r--r--drivers/media/i2c/mt9p031.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index a27166277dee..fec76d3f056c 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -78,6 +78,9 @@
78#define MT9P031_PLL_CONFIG_1 0x11 78#define MT9P031_PLL_CONFIG_1 0x11
79#define MT9P031_PLL_CONFIG_2 0x12 79#define MT9P031_PLL_CONFIG_2 0x12
80#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a 80#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a
81#define MT9P031_PIXEL_CLOCK_INVERT (1 << 15)
82#define MT9P031_PIXEL_CLOCK_SHIFT(n) ((n) << 8)
83#define MT9P031_PIXEL_CLOCK_DIVIDE(n) ((n) << 0)
81#define MT9P031_FRAME_RESTART 0x0b 84#define MT9P031_FRAME_RESTART 0x0b
82#define MT9P031_SHUTTER_DELAY 0x0c 85#define MT9P031_SHUTTER_DELAY 0x0c
83#define MT9P031_RST 0x0d 86#define MT9P031_RST 0x0d
@@ -130,6 +133,8 @@ struct mt9p031 {
130 133
131 enum mt9p031_model model; 134 enum mt9p031_model model;
132 struct aptina_pll pll; 135 struct aptina_pll pll;
136 unsigned int clk_div;
137 bool use_pll;
133 int reset; 138 int reset;
134 139
135 struct v4l2_ctrl_handler ctrls; 140 struct v4l2_ctrl_handler ctrls;
@@ -198,6 +203,11 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
198 if (ret < 0) 203 if (ret < 0)
199 return ret; 204 return ret;
200 205
206 ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL,
207 MT9P031_PIXEL_CLOCK_DIVIDE(mt9p031->clk_div));
208 if (ret < 0)
209 return ret;
210
201 return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN, 211 return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN,
202 0); 212 0);
203} 213}
@@ -229,8 +239,24 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
229 239
230 clk_set_rate(mt9p031->clk, pdata->ext_freq); 240 clk_set_rate(mt9p031->clk, pdata->ext_freq);
231 241
242 /* If the external clock frequency is out of bounds for the PLL use the
243 * pixel clock divider only and disable the PLL.
244 */
245 if (pdata->ext_freq > limits.ext_clock_max) {
246 unsigned int div;
247
248 div = DIV_ROUND_UP(pdata->ext_freq, pdata->target_freq);
249 div = roundup_pow_of_two(div) / 2;
250
251 mt9p031->clk_div = max_t(unsigned int, div, 64);
252 mt9p031->use_pll = false;
253
254 return 0;
255 }
256
232 mt9p031->pll.ext_clock = pdata->ext_freq; 257 mt9p031->pll.ext_clock = pdata->ext_freq;
233 mt9p031->pll.pix_clock = pdata->target_freq; 258 mt9p031->pll.pix_clock = pdata->target_freq;
259 mt9p031->use_pll = true;
234 260
235 return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll); 261 return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
236} 262}
@@ -240,6 +266,9 @@ static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
240 struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); 266 struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
241 int ret; 267 int ret;
242 268
269 if (!mt9p031->use_pll)
270 return 0;
271
243 ret = mt9p031_write(client, MT9P031_PLL_CONTROL, 272 ret = mt9p031_write(client, MT9P031_PLL_CONTROL,
244 MT9P031_PLL_CONTROL_PWRON); 273 MT9P031_PLL_CONTROL_PWRON);
245 if (ret < 0) 274 if (ret < 0)
@@ -265,6 +294,9 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
265{ 294{
266 struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); 295 struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
267 296
297 if (!mt9p031->use_pll)
298 return 0;
299
268 return mt9p031_write(client, MT9P031_PLL_CONTROL, 300 return mt9p031_write(client, MT9P031_PLL_CONTROL,
269 MT9P031_PLL_CONTROL_PWROFF); 301 MT9P031_PLL_CONTROL_PWROFF);
270} 302}