summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/mt9p031.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-04 09:50:07 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-04 09:50:07 -0700
commit3c83e61e67256e0bb08c46cc2db43b58fd617251 (patch)
tree0233e1e04e6449c60b01ff5dea8bea85bcf22f08 /drivers/media/i2c/mt9p031.c
parent4a4389abdd9822fdf3cc2ac6ed87eb811fd43acc (diff)
parenta83b93a7480441a47856dc9104bea970e84cda87 (diff)
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: "The main set of series of patches for media subsystem, including: - document RC sysfs class - added an API to setup scancode to allow waking up systems using the Remote Controller - add API for SDR devices. Drivers are still on staging - some API improvements for getting EDID data from media inputs/outputs - new DVB frontend driver for drx-j (ATSC) - one driver (it913x/it9137) got removed, in favor of an improvement on another driver (af9035) - added a skeleton V4L2 PCI driver at documentation - added a dual flash driver (lm3646) - added a new IR driver (img-ir) - added an IR scancode decoder for the Sharp protocol - some improvements at the usbtv driver, to allow its core to be reused. - added a new SDR driver (rtl2832u_sdr) - added a new tuner driver (msi001) - several improvements at em28xx driver to fix PM support, device removal and to split the V4L2 specific bits into a separate sub-driver - one driver got converted to videobuf2 (s2255drv) - the e4000 tuner driver now follows an improved binding model - some fixes at V4L2 compat32 code - several fixes and enhancements at videobuf2 code - some cleanups at V4L2 API documentation - usual driver enhancements, new board additions and misc fixups" [ NOTE! This merge effective drops commit 4329b93b283c ("of: Reduce indentation in of_graph_get_next_endpoint"). The of_graph_get_next_endpoint() function was moved and renamed by commit fd9fdb78a9bf ("[media] of: move graph helpers from drivers/media/v4l2-core to drivers/of"). It was originally called v4l2_of_get_next_endpoint() and lived in the file drivers/media/v4l2-core/v4l2-of.c. In that original location, it was then fixed to support empty port nodes by commit b9db140c1e46 ("[media] v4l: of: Support empty port nodes"), and that commit clashes badly with the dropped "Reduce intendation" commit. I had to choose one or the other, and decided that the "Support empty port nodes" commit was more important ] * 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (426 commits) [media] em28xx-dvb: fix PCTV 461e tuner I2C binding Revert "[media] em28xx-dvb: fix PCTV 461e tuner I2C binding" [media] em28xx: fix PCTV 290e LNA oops [media] em28xx-dvb: fix PCTV 461e tuner I2C binding [media] m88ds3103: fix bug on .set_tone() [media] saa7134: fix WARN_ON during resume [media] v4l2-dv-timings: add module name, description, license [media] videodev2.h: add parenthesis around macro arguments [media] saa6752hs: depends on CRC32 [media] si4713: fix Kconfig dependencies [media] Sensoray 2255 uses videobuf2 [media] adv7180: free an interrupt on failure paths in init_device() [media] e4000: make VIDEO_V4L2 dependency optional [media] af9033: Don't export functions for the hardware filter [media] af9035: use af9033 PID filters [media] af9033: implement PID filter [media] rtl2832_sdr: do not use dynamic stack allocation [media] e4000: fix 32-bit build error [media] em28xx-audio: make sure audio is unmuted on open() [media] DocBook media: v4l2_format_sdr was renamed to v4l2_sdr_format ...
Diffstat (limited to 'drivers/media/i2c/mt9p031.c')
-rw-r--r--drivers/media/i2c/mt9p031.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 192c4aad05d6..33daace81297 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 @@ struct mt9p031 {
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 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
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);
}
@@ -222,15 +232,34 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
struct mt9p031_platform_data *pdata = mt9p031->pdata;
+ int ret;
mt9p031->clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(mt9p031->clk))
return PTR_ERR(mt9p031->clk);
- clk_set_rate(mt9p031->clk, pdata->ext_freq);
+ ret = clk_set_rate(mt9p031->clk, pdata->ext_freq);
+ if (ret < 0)
+ return ret;
+
+ /* 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 +269,9 @@ static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
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 +297,9 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
{
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);
}
@@ -285,9 +320,15 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
if (ret < 0)
return ret;
- /* Emable clock */
- if (mt9p031->clk)
- clk_prepare_enable(mt9p031->clk);
+ /* Enable clock */
+ if (mt9p031->clk) {
+ ret = clk_prepare_enable(mt9p031->clk);
+ if (ret) {
+ regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators),
+ mt9p031->regulators);
+ return ret;
+ }
+ }
/* Now RESET_BAR must be high */
if (gpio_is_valid(mt9p031->reset)) {