diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-12-11 11:28:37 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-12-11 11:28:37 -0200 |
commit | 77c53d0b56264a8fc5844e087ad15fffe20c299d (patch) | |
tree | 61925f42355feabc010c53172212742ec3651d4f /drivers/media/i2c | |
parent | 9374020a78fce13a1cf2edf3d26f6dd7231b5c3d (diff) | |
parent | d8658bca2e5696df2b6c69bc5538f8fe54e4a01e (diff) |
Merge branch 'for_3.8-rc1' into v4l_for_linus
* for_3.8-rc1: (243 commits)
[media] omap3isp: Replace cpu_is_omap3630() with ISP revision check
[media] omap3isp: Prepare/unprepare clocks before/after enable/disable
[media] omap3isp: preview: Add support for 8-bit formats at the sink pad
[media] omap3isp: Replace printk with dev_*
[media] omap3isp: Find source pad from external entity
[media] omap3isp: Configure CSI-2 phy based on platform data
[media] omap3isp: Add PHY routing configuration
[media] omap3isp: Add CSI configuration registers from control block to ISP resources
[media] omap3isp: Remove unneeded module memory address definitions
[media] omap3isp: Use monotonic timestamps for statistics buffers
[media] uvcvideo: Fix control value clamping for unsigned integer controls
[media] uvcvideo: Mark first output terminal as default video node
[media] uvcvideo: Add VIDIOC_[GS]_PRIORITY support
[media] uvcvideo: Return -ENOTTY for unsupported ioctls
[media] uvcvideo: Set device_caps in VIDIOC_QUERYCAP
[media] uvcvideo: Don't fail when an unsupported format is requested
[media] uvcvideo: Return -EACCES when trying to access a read/write-only control
[media] uvcvideo: Set error_idx properly for extended controls API failures
[media] rtl28xxu: add NOXON DAB/DAB+ USB dongle rev 2
[media] fc2580: write some registers conditionally
...
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r-- | drivers/media/i2c/adp1653.c | 4 | ||||
-rw-r--r-- | drivers/media/i2c/adv7183.c | 13 | ||||
-rw-r--r-- | drivers/media/i2c/adv7604.c | 16 | ||||
-rw-r--r-- | drivers/media/i2c/cx25840/cx25840-core.c | 2 | ||||
-rw-r--r-- | drivers/media/i2c/ir-kbd-i2c.c | 14 | ||||
-rw-r--r-- | drivers/media/i2c/s5k4ecgx.c | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp-pll.c | 219 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp-pll.h | 61 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-core.c | 74 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-limits.c | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-limits.h | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-quirk.c | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-quirk.h | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-reg-defs.h | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-reg.h | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-regs.c | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-regs.h | 2 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp.h | 2 | ||||
-rw-r--r-- | drivers/media/i2c/soc_camera/mt9v022.c | 88 | ||||
-rw-r--r-- | drivers/media/i2c/soc_camera/ov2640.c | 55 | ||||
-rw-r--r-- | drivers/media/i2c/vs6624.c | 13 |
21 files changed, 349 insertions, 230 deletions
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 18a38b38fcb..df163800c8e 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -3,10 +3,10 @@ * * Copyright (C) 2008--2011 Nokia Corporation * - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * Contributors: - * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Sakari Ailus <sakari.ailus@iki.fi> * Tuukka Toivonen <tuukkat76@gmail.com> * * This program is free software; you can redistribute it and/or diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index e1d4c89d714..10c3c1db4cd 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -681,18 +681,7 @@ static struct i2c_driver adv7183_driver = { .id_table = adv7183_id, }; -static __init int adv7183_init(void) -{ - return i2c_add_driver(&adv7183_driver); -} - -static __exit void adv7183_exit(void) -{ - i2c_del_driver(&adv7183_driver); -} - -module_init(adv7183_init); -module_exit(adv7183_exit); +module_i2c_driver(adv7183_driver); MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver"); MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 05f8950f6f9..f47555b1000 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -486,9 +486,19 @@ static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) struct i2c_client *client = state->i2c_edid; u8 msgbuf0[1] = { 0 }; u8 msgbuf1[256]; - struct i2c_msg msg[2] = { { client->addr, 0, 1, msgbuf0 }, - { client->addr, 0 | I2C_M_RD, len, msgbuf1 } - }; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .len = 1, + .buf = msgbuf0 + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = msgbuf1 + }, + }; if (i2c_transfer(client->adapter, msg, 2) < 0) return -EIO; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 2cee69e3418..f4149eb4d7b 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -2065,7 +2065,7 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, #define DIF_BPF_COEFF3435 (0x38c) #define DIF_BPF_COEFF36 (0x390) -void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) +static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) { u64 pll_freq; u32 pll_freq_word; diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 04f192a0398..08ae067b2b6 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -284,7 +284,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { char *ir_codes = NULL; const char *name = NULL; - u64 rc_type = RC_TYPE_UNKNOWN; + u64 rc_type = RC_BIT_UNKNOWN; struct IR_i2c *ir; struct rc_dev *rc = NULL; struct i2c_adapter *adap = client->adapter; @@ -303,7 +303,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) case 0x64: name = "Pixelview"; ir->get_key = get_key_pixelview; - rc_type = RC_TYPE_OTHER; + rc_type = RC_BIT_OTHER; ir_codes = RC_MAP_EMPTY; break; case 0x18: @@ -311,31 +311,31 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) case 0x1a: name = "Hauppauge"; ir->get_key = get_key_haup; - rc_type = RC_TYPE_RC5; + rc_type = RC_BIT_RC5; ir_codes = RC_MAP_HAUPPAUGE; break; case 0x30: name = "KNC One"; ir->get_key = get_key_knc1; - rc_type = RC_TYPE_OTHER; + rc_type = RC_BIT_OTHER; ir_codes = RC_MAP_EMPTY; break; case 0x6b: name = "FusionHDTV"; ir->get_key = get_key_fusionhdtv; - rc_type = RC_TYPE_RC5; + rc_type = RC_BIT_RC5; ir_codes = RC_MAP_FUSIONHDTV_MCE; break; case 0x40: name = "AVerMedia Cardbus remote"; ir->get_key = get_key_avermedia_cardbus; - rc_type = RC_TYPE_OTHER; + rc_type = RC_BIT_OTHER; ir_codes = RC_MAP_AVERMEDIA_CARDBUS; break; case 0x71: name = "Hauppauge/Zilog Z8"; ir->get_key = get_key_haup_xvr; - rc_type = RC_TYPE_RC5; + rc_type = RC_BIT_RC5; ir_codes = RC_MAP_HAUPPAUGE; break; } diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index 49c1b3abb42..2750de63427 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -343,7 +343,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) } regs_num = le32_to_cpu(get_unaligned_le32(fw->data)); - v4l2_dbg(3, debug, sd, "FW: %s size %d register sets %d\n", + v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n", S5K4ECGX_FIRMWARE, fw->size, regs_num); regs_num++; /* Add header */ diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index a577614bd84..d8d5da7c52d 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -58,7 +58,7 @@ static int bounds_check(struct device *dev, uint32_t val, if (val >= min && val <= max) return 0; - dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); + dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); return -EINVAL; } @@ -87,14 +87,14 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll) dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz); } -int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, - struct smiapp_pll *pll) +static int __smiapp_pll_calculate(struct device *dev, + const struct smiapp_pll_limits *limits, + struct smiapp_pll *pll, uint32_t mul, + uint32_t div, uint32_t lane_op_clock_ratio) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; uint32_t vt_op_binning_div; - uint32_t lane_op_clock_ratio; - uint32_t mul, div; uint32_t more_mul_min, more_mul_max; uint32_t more_mul_factor; uint32_t min_vt_div, max_vt_div, vt_div; @@ -102,54 +102,6 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, unsigned int i; int rval; - if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) - lane_op_clock_ratio = pll->lanes; - else - lane_op_clock_ratio = 1; - dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio); - - dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal, - pll->binning_vertical); - - /* CSI transfers 2 bits per clock per lane; thus times 2 */ - pll->pll_op_clk_freq_hz = pll->link_freq * 2 - * (pll->lanes / lane_op_clock_ratio); - - /* Figure out limits for pre-pll divider based on extclk */ - dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - limits->max_pre_pll_clk_div = - min_t(uint16_t, limits->max_pre_pll_clk_div, - clk_div_even(pll->ext_clk_freq_hz / - limits->min_pll_ip_freq_hz)); - limits->min_pre_pll_clk_div = - max_t(uint16_t, limits->min_pre_pll_clk_div, - clk_div_even_up( - DIV_ROUND_UP(pll->ext_clk_freq_hz, - limits->max_pll_ip_freq_hz))); - dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - - i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); - mul = div_u64(pll->pll_op_clk_freq_hz, i); - div = pll->ext_clk_freq_hz / i; - dev_dbg(dev, "mul %d / div %d\n", mul, div); - - limits->min_pre_pll_clk_div = - max_t(uint16_t, limits->min_pre_pll_clk_div, - clk_div_even_up( - DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, - limits->max_pll_op_freq_hz))); - dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - - if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) { - dev_err(dev, "unable to compute pre_pll divisor\n"); - return -EINVAL; - } - - pll->pre_pll_clk_div = limits->min_pre_pll_clk_div; - /* * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be * too high. @@ -162,7 +114,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, more_mul_max); /* Don't go above max pll op frequency. */ more_mul_max = - min_t(int, + min_t(uint32_t, more_mul_max, limits->max_pll_op_freq_hz / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); @@ -170,7 +122,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, more_mul_max); /* Don't go above the division capability of op sys clock divider. */ more_mul_max = min(more_mul_max, - limits->max_op_sys_clk_div * pll->pre_pll_clk_div + limits->op.max_sys_clk_div * pll->pre_pll_clk_div / div); dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n", more_mul_max); @@ -193,14 +145,14 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, more_mul_min); if (more_mul_min > more_mul_max) { - dev_warn(dev, - "unable to compute more_mul_min and more_mul_max"); + dev_dbg(dev, + "unable to compute more_mul_min and more_mul_max\n"); return -EINVAL; } more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor); - more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div); + more_mul_factor = lcm(more_mul_factor, limits->op.min_sys_clk_div); dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", more_mul_factor); i = roundup(more_mul_min, more_mul_factor); @@ -209,7 +161,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, dev_dbg(dev, "final more_mul: %d\n", i); if (i > more_mul_max) { - dev_warn(dev, "final more_mul is bad, max %d", more_mul_max); + dev_dbg(dev, "final more_mul is bad, max %d\n", more_mul_max); return -EINVAL; } @@ -268,19 +220,19 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, dev_dbg(dev, "min_vt_div: %d\n", min_vt_div); min_vt_div = max(min_vt_div, DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->max_vt_pix_clk_freq_hz)); + limits->vt.max_pix_clk_freq_hz)); dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n", min_vt_div); min_vt_div = max_t(uint32_t, min_vt_div, - limits->min_vt_pix_clk_div - * limits->min_vt_sys_clk_div); + limits->vt.min_pix_clk_div + * limits->vt.min_sys_clk_div); dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div); - max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div; + max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; dev_dbg(dev, "max_vt_div: %d\n", max_vt_div); max_vt_div = min(max_vt_div, DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->min_vt_pix_clk_freq_hz)); + limits->vt.min_pix_clk_freq_hz)); dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n", max_vt_div); @@ -288,28 +240,28 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, * Find limitsits for sys_clk_div. Not all values are possible * with all values of pix_clk_div. */ - min_sys_div = limits->min_vt_sys_clk_div; + min_sys_div = limits->vt.min_sys_clk_div; dev_dbg(dev, "min_sys_div: %d\n", min_sys_div); min_sys_div = max(min_sys_div, DIV_ROUND_UP(min_vt_div, - limits->max_vt_pix_clk_div)); + limits->vt.max_pix_clk_div)); dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div); min_sys_div = max(min_sys_div, pll->pll_op_clk_freq_hz - / limits->max_vt_sys_clk_freq_hz); + / limits->vt.max_sys_clk_freq_hz); dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div); min_sys_div = clk_div_even_up(min_sys_div); dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div); - max_sys_div = limits->max_vt_sys_clk_div; + max_sys_div = limits->vt.max_sys_clk_div; dev_dbg(dev, "max_sys_div: %d\n", max_sys_div); max_sys_div = min(max_sys_div, DIV_ROUND_UP(max_vt_div, - limits->min_vt_pix_clk_div)); + limits->vt.min_pix_clk_div)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div); max_sys_div = min(max_sys_div, DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->min_vt_pix_clk_freq_hz)); + limits->vt.min_pix_clk_freq_hz)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div); /* @@ -322,15 +274,15 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, for (sys_div = min_sys_div; sys_div <= max_sys_div; sys_div += 2 - (sys_div & 1)) { - int pix_div = DIV_ROUND_UP(vt_div, sys_div); + uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); - if (pix_div < limits->min_vt_pix_clk_div - || pix_div > limits->max_vt_pix_clk_div) { + if (pix_div < limits->vt.min_pix_clk_div + || pix_div > limits->vt.max_pix_clk_div) { dev_dbg(dev, "pix_div %d too small or too big (%d--%d)\n", pix_div, - limits->min_vt_pix_clk_div, - limits->max_vt_pix_clk_div); + limits->vt.min_pix_clk_div, + limits->vt.max_pix_clk_div); continue; } @@ -354,16 +306,10 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, pll->pixel_rate_csi = pll->op_pix_clk_freq_hz * lane_op_clock_ratio; - print_pll(dev, pll); - - rval = bounds_check(dev, pll->pre_pll_clk_div, - limits->min_pre_pll_clk_div, - limits->max_pre_pll_clk_div, "pre_pll_clk_div"); - if (!rval) - rval = bounds_check( - dev, pll->pll_ip_clk_freq_hz, - limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz, - "pll_ip_clk_freq_hz"); + rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, + limits->min_pll_ip_freq_hz, + limits->max_pll_ip_freq_hz, + "pll_ip_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->pll_multiplier, @@ -377,42 +323,121 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, if (!rval) rval = bounds_check( dev, pll->op_sys_clk_div, - limits->min_op_sys_clk_div, limits->max_op_sys_clk_div, + limits->op.min_sys_clk_div, limits->op.max_sys_clk_div, "op_sys_clk_div"); if (!rval) rval = bounds_check( dev, pll->op_pix_clk_div, - limits->min_op_pix_clk_div, limits->max_op_pix_clk_div, + limits->op.min_pix_clk_div, limits->op.max_pix_clk_div, "op_pix_clk_div"); if (!rval) rval = bounds_check( dev, pll->op_sys_clk_freq_hz, - limits->min_op_sys_clk_freq_hz, - limits->max_op_sys_clk_freq_hz, + limits->op.min_sys_clk_freq_hz, + limits->op.max_sys_clk_freq_hz, "op_sys_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->op_pix_clk_freq_hz, - limits->min_op_pix_clk_freq_hz, - limits->max_op_pix_clk_freq_hz, + limits->op.min_pix_clk_freq_hz, + limits->op.max_pix_clk_freq_hz, "op_pix_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->vt_sys_clk_freq_hz, - limits->min_vt_sys_clk_freq_hz, - limits->max_vt_sys_clk_freq_hz, + limits->vt.min_sys_clk_freq_hz, + limits->vt.max_sys_clk_freq_hz, "vt_sys_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->vt_pix_clk_freq_hz, - limits->min_vt_pix_clk_freq_hz, - limits->max_vt_pix_clk_freq_hz, + limits->vt.min_pix_clk_freq_hz, + limits->vt.max_pix_clk_freq_hz, "vt_pix_clk_freq_hz"); return rval; } + +int smiapp_pll_calculate(struct device *dev, + const struct smiapp_pll_limits *limits, + struct smiapp_pll *pll) +{ + uint16_t min_pre_pll_clk_div; + uint16_t max_pre_pll_clk_div; + uint32_t lane_op_clock_ratio; + uint32_t mul, div; + unsigned int i; + int rval = -EINVAL; + + if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) + lane_op_clock_ratio = pll->csi2.lanes; + else + lane_op_clock_ratio = 1; + dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio); + + dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal, + pll->binning_vertical); + + switch (pll->bus_type) { + case SMIAPP_PLL_BUS_TYPE_CSI2: + /* CSI transfers 2 bits per clock per lane; thus times 2 */ + pll->pll_op_clk_freq_hz = pll->link_freq * 2 + * (pll->csi2.lanes / lane_op_clock_ratio); + break; + case SMIAPP_PLL_BUS_TYPE_PARALLEL: + pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel + / DIV_ROUND_UP(pll->bits_per_pixel, + pll->parallel.bus_width); + break; + default: + return -EINVAL; + } + + /* Figure out limits for pre-pll divider based on extclk */ + dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n", + limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); + max_pre_pll_clk_div = + min_t(uint16_t, limits->max_pre_pll_clk_div, + clk_div_even(pll->ext_clk_freq_hz / + limits->min_pll_ip_freq_hz)); + min_pre_pll_clk_div = + max_t(uint16_t, limits->min_pre_pll_clk_div, + clk_div_even_up( + DIV_ROUND_UP(pll->ext_clk_freq_hz, + limits->max_pll_ip_freq_hz))); + dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); + + i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); + mul = div_u64(pll->pll_op_clk_freq_hz, i); + div = pll->ext_clk_freq_hz / i; + dev_dbg(dev, "mul %d / div %d\n", mul, div); + + min_pre_pll_clk_div = + max_t(uint16_t, min_pre_pll_clk_div, + clk_div_even_up( + DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, + limits->max_pll_op_freq_hz))); + dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); + + for (pll->pre_pll_clk_div = min_pre_pll_clk_div; + pll->pre_pll_clk_div <= max_pre_pll_clk_div; + pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { + rval = __smiapp_pll_calculate(dev, limits, pll, mul, div, + lane_op_clock_ratio); + if (rval) + continue; + + print_pll(dev, pll); + return 0; + } + + dev_info(dev, "unable to compute pre_pll divisor\n"); + return rval; +} EXPORT_SYMBOL_GPL(smiapp_pll_calculate); -MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>"); MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h index cb2d2db5d02..a4a649834a1 100644 --- a/drivers/media/i2c/smiapp-pll.h +++ b/drivers/media/i2c/smiapp-pll.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,16 +27,34 @@ #include <linux/device.h> +/* CSI-2 or CCP-2 */ +#define SMIAPP_PLL_BUS_TYPE_CSI2 0x00 +#define SMIAPP_PLL_BUS_TYPE_PARALLEL 0x01 + +/* op pix clock is for all lanes in total normally */ +#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) +#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1) + struct smiapp_pll { - uint8_t lanes; + /* input values */ + uint8_t bus_type; + union { + struct { + uint8_t lanes; + } csi2; + struct { + uint8_t bus_width; + } parallel; + }; + uint8_t flags; uint8_t binning_horizontal; uint8_t binning_vertical; uint8_t scale_m; uint8_t scale_n; uint8_t bits_per_pixel; - uint16_t flags; uint32_t link_freq; + /* output values */ uint16_t pre_pll_clk_div; uint16_t pll_multiplier; uint16_t op_sys_clk_div; @@ -55,6 +73,17 @@ struct smiapp_pll { uint32_t pixel_rate_csi; }; +struct smiapp_pll_branch_limits { + uint16_t min_sys_clk_div; + uint16_t max_sys_clk_div; + uint32_t min_sys_clk_freq_hz; + uint32_t max_sys_clk_freq_hz; + uint16_t min_pix_clk_div; + uint16_t max_pix_clk_div; + uint32_t min_pix_clk_freq_hz; + uint32_t max_pix_clk_freq_hz; +}; + struct smiapp_pll_limits { /* Strict PLL limits */ uint32_t min_ext_clk_freq_hz; @@ -68,36 +97,18 @@ struct smiapp_pll_limits { uint32_t min_pll_op_freq_hz; uint32_t max_pll_op_freq_hz; - uint16_t min_vt_sys_clk_div; - uint16_t max_vt_sys_clk_div; - uint32_t min_vt_sys_clk_freq_hz; - uint32_t max_vt_sys_clk_freq_hz; - uint16_t min_vt_pix_clk_div; - uint16_t max_vt_pix_clk_div; - uint32_t min_vt_pix_clk_freq_hz; - uint32_t max_vt_pix_clk_freq_hz; - - uint16_t min_op_sys_clk_div; - uint16_t max_op_sys_clk_div; - uint32_t min_op_sys_clk_freq_hz; - uint32_t max_op_sys_clk_freq_hz; - uint16_t min_op_pix_clk_div; - uint16_t max_op_pix_clk_div; - uint32_t min_op_pix_clk_freq_hz; - uint32_t max_op_pix_clk_freq_hz; + struct smiapp_pll_branch_limits vt; + struct smiapp_pll_branch_limits op; /* Other relevant limits */ uint32_t min_line_length_pck_bin; uint32_t min_line_length_pck; }; -/* op pix clock is for all lanes in total normally */ -#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) -#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1) - struct device; -int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, +int smiapp_pll_calculate(struct device *dev, + const struct smiapp_pll_limits *limits, struct smiapp_pll *pll); #endif /* SMIAPP_PLL_H */ diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index e08e588ad24..83c7ed7ffcc 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * Based on smiapp driver by Vimarsh Zutshi * Based on jt8ev1.c by Vimarsh Zutshi @@ -252,23 +252,23 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ], .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ], - .min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV], - .max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV], - .min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV], - .max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV], - .min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ], - .max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ], - .min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ], - .max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ], - - .min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV], - .max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV], - .min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV], - .max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV], - .min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ], - .max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ], - .min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ], - .max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ], + .op.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV], + .op.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV], + .op.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV], + .op.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV], + .op.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ], + .op.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ], + .op.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ], + .op.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ], + + .vt.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV], + .vt.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV], + .vt.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV], + .vt.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV], + .vt.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ], + .vt.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ], + .vt.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ], + .vt.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ], .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN], .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK], @@ -276,11 +276,6 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) struct smiapp_pll *pll = &sensor->pll; int rval; - memset(&sensor->pll, 0, sizeof(sensor->pll)); - - pll->lanes = sensor->platform_data->lanes; - pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; - if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) { /* * Fill in operational clock divisors limits from the @@ -288,28 +283,14 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) * requirements regarding them are essentially the * same as on VT ones. */ - lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div; - lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div; - lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div; - lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div; - lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz; - lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz; - lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz; - lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz; - /* Profile 0 sensors have no separate OP clock branch. */ - pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + lim.op = lim.vt; } - if (smiapp_needs_quirk(sensor, - SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE)) - pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; - pll->binning_horizontal = sensor->binning_horizontal; pll->binning_vertical = sensor->binning_vertical; pll->link_freq = sensor->link_freq->qmenu_int[sensor->link_freq->val]; pll->scale_m = sensor->scale_m; - pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; pll->bits_per_pixel = sensor->csi_format->compressed; rval = smiapp_pll_calculate(&client->dev, &lim, pll); @@ -1010,7 +991,7 @@ static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) * do not change, or if you do at least know what you're * doing. :-) * - * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25 + * Sakari Ailus <sakari.ailus@iki.fi> 2010-10-25 * * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl * / EXTCLK freq [Hz]) * flash_strobe_adjustment @@ -2369,6 +2350,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct smiapp_pll *pll = &sensor->pll; struct smiapp_subdev *last = NULL; u32 tmp; unsigned int i; @@ -2635,6 +2617,18 @@ static int smiapp_registered(struct v4l2_subdev *subdev) if (rval < 0) goto out_nvm_release; + /* prepare PLL configuration input values */ + pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; + pll->csi2.lanes = sensor->platform_data->lanes; + pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; + /* Profile 0 sensors have no separate OP clock branch. */ + if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + if (smiapp_needs_quirk(sensor, + SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE)) + pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; + rval = smiapp_update_mode(sensor); if (rval) { dev_err(&client->dev, "update mode failed\n"); @@ -2893,6 +2887,6 @@ static struct i2c_driver smiapp_i2c_driver = { module_i2c_driver(smiapp_i2c_driver); -MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>"); MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c index fb2f81ad8c3..847cb235e19 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.c +++ b/drivers/media/i2c/smiapp/smiapp-limits.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h index 9ae765e23ea..343e9c3827f 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.h +++ b/drivers/media/i2c/smiapp/smiapp-limits.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index 725cf62836c..bb8c506e0e3 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h index 86fd3e8bfb0..504a6d80ced 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h index defa7c5adeb..3aa0ca948d8 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h +++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h index 54568ca2fe6..b0dcbb8fa5e 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg.h +++ b/drivers/media/i2c/smiapp/smiapp-reg.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index 70e0d8db013..4fac32cfcb3 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h index 7f9013b4797..eefc6c84d5f 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ b/drivers/media/i2c/smiapp/smiapp-regs.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 4182a695ab5..7cc5aae662f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 333ef178d6f..d40a8858be0 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -15,6 +15,7 @@ #include <linux/log2.h> #include <linux/module.h> +#include <media/mt9v022.h> #include <media/soc_camera.h> #include <media/soc_mediabus.h> #include <media/v4l2-subdev.h> @@ -50,6 +51,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); #define MT9V022_PIXEL_OPERATION_MODE 0x0f #define MT9V022_LED_OUT_CONTROL 0x1b #define MT9V022_ADC_MODE_CONTROL 0x1c +#define MT9V022_REG32 0x20 #define MT9V022_ANALOG_GAIN 0x35 #define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 #define MT9V022_PIXCLK_FV_LV 0x74 @@ -71,7 +73,15 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); #define MT9V022_COLUMN_SKIP 1 #define MT9V022_ROW_SKIP 4 -#define is_mt9v024(id) (id == 0x1324) +#define MT9V022_HORIZONTAL_BLANKING_MIN 43 +#define MT9V022_HORIZONTAL_BLANKING_MAX 1023 +#define MT9V022_HORIZONTAL_BLANKING_DEF 94 +#define MT9V022_VERTICAL_BLANKING_MIN 2 +#define MT9V022_VERTICAL_BLANKING_MAX 3000 +#define MT9V022_VERTICAL_BLANKING_DEF 45 + +#define is_mt9v022_rev3(id) (id == 0x1313) +#define is_mt9v024(id) (id == 0x1324) /* MT9V022 has only one fixed colorspace per pixelcode */ struct mt9v022_datafmt { @@ -136,6 +146,8 @@ struct mt9v022 { struct v4l2_ctrl *autogain; struct v4l2_ctrl *gain; }; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; struct v4l2_rect rect; /* Sensor window */ const struct mt9v022_datafmt *fmt; const struct mt9v022_datafmt *fmts; @@ -143,6 +155,7 @@ struct mt9v022 { int num_fmts; int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ u16 chip_control; + u16 chip_version; unsigned short y_skip_top; /* Lines to skip at the top */ }; @@ -225,12 +238,32 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); - if (enable) + if (enable) { /* Switch to master "normal" mode */ mt9v022->chip_control &= ~0x10; - else + if (is_mt9v022_rev3(mt9v022->chip_version) || + is_mt9v024(mt9v022->chip_version)) { + /* + * Unset snapshot mode specific settings: clear bit 9 + * and bit 2 in reg. 0x20 when in normal mode. + */ + if (reg_clear(client, MT9V022_REG32, 0x204)) + return -EIO; + } + } else { /* Switch to snapshot mode */ mt9v022->chip_control |= 0x10; + if (is_mt9v022_rev3(mt9v022->chip_version) || + is_mt9v024(mt9v022->chip_version)) { + /* + * Required settings for snapshot mode: set bit 9 + * (RST enable) and bit 2 (CR enable) in reg. 0x20 + * See TechNote TN0960 or TN-09-225. + */ + if (reg_set(client, MT9V022_REG32, 0x204)) + return -EIO; + } + } if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) return -EIO; @@ -282,11 +315,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) * Default 94, Phytec driver says: * "width + horizontal blank >= 660" */ - ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, - rect.width > 660 - 43 ? 43 : - 660 - rect.width); + ret = v4l2_ctrl_s_ctrl(mt9v022->hblank, + rect.width > 660 - 43 ? 43 : 660 - rect.width); if (!ret) - ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); + ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45); if (!ret) ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); if (!ret) @@ -509,6 +541,18 @@ static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) range = exp->maximum - exp->minimum; exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; return 0; + case V4L2_CID_HBLANK: + data = reg_read(client, MT9V022_HORIZONTAL_BLANKING); + if (data < 0) + return -EIO; + ctrl->val = data; + return 0; + case V4L2_CID_VBLANK: + data = reg_read(client, MT9V022_VERTICAL_BLANKING); + if (data < 0) + return -EIO; + ctrl->val = data; + return 0; } return -EINVAL; } @@ -590,6 +634,16 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) return -EIO; } return 0; + case V4L2_CID_HBLANK: + if (reg_write(client, MT9V022_HORIZONTAL_BLANKING, + ctrl->val) < 0) + return -EIO; + return 0; + case V4L2_CID_VBLANK: + if (reg_write(client, MT9V022_VERTICAL_BLANKING, + ctrl->val) < 0) + return -EIO; + return 0; } return -EINVAL; } @@ -621,6 +675,8 @@ static int mt9v022_video_probe(struct i2c_client *client) goto ei2c; } + mt9v022->chip_version = data; + mt9v022->reg = is_mt9v024(data) ? &mt9v024_register : &mt9v022_register; @@ -819,6 +875,7 @@ static int mt9v022_probe(struct i2c_client *client, struct mt9v022 *mt9v022; struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct mt9v022_platform_data *pdata = icl->priv; int ret; if (!icl) { @@ -857,10 +914,21 @@ static int mt9v022_probe(struct i2c_client *client, mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE, 1, 255, 1, 255); + mt9v022->hblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_HBLANK, MT9V022_HORIZONTAL_BLANKING_MIN, + MT9V022_HORIZONTAL_BLANKING_MAX, 1, + MT9V022_HORIZONTAL_BLANKING_DEF); + + mt9v022->vblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_VBLANK, MT9V022_VERTICAL_BLANKING_MIN, + MT9V022_VERTICAL_BLANKING_MAX, 1, + MT9V022_VERTICAL_BLANKING_DEF); + mt9v022->subdev.ctrl_handler = &mt9v022->hdl; if (mt9v022->hdl.error) { int err = mt9v022->hdl.error; + dev_err(&client->dev, "control initialisation err %d\n", err); kfree(mt9v022); return err; } @@ -871,10 +939,10 @@ static int mt9v022_probe(struct i2c_client *client, mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; /* - * MT9V022 _really_ corrupts the first read out line. - * TODO: verify on i.MX31 + * On some platforms the first read out line is corrupted. + * Workaround it by skipping if indicated by platform data. */ - mt9v022->y_skip_top = 1; + mt9v022->y_skip_top = pdata ? pdata->y_skip_top : 0; mt9v022->rect.left = MT9V022_COLUMN_SKIP; mt9v022->rect.top = MT9V022_ROW_SKIP; mt9v022->rect.width = MT9V022_MAX_WIDTH; diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index d2d298b6354..66698a83bda 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -586,9 +586,20 @@ static const struct regval_list ov2640_format_change_preamble_regs[] = { ENDMARKER, }; -static const struct regval_list ov2640_yuv422_regs[] = { +static const struct regval_list ov2640_yuyv_regs[] = { + { IMAGE_MODE, IMAGE_MODE_YUV422 }, + { 0xd7, 0x03 }, + { 0x33, 0xa0 }, + { 0xe5, 0x1f }, + { 0xe1, 0x67 }, + { RESET, 0x00 }, + { R_BYPASS, R_BYPASS_USE_DSP }, + ENDMARKER, +}; + +static const struct regval_list ov2640_uyvy_regs[] = { { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 }, - { 0xD7, 0x01 }, + { 0xd7, 0x01 }, { 0x33, 0xa0 }, { 0xe1, 0x67 }, { RESET, 0x00 }, @@ -596,7 +607,15 @@ static const struct regval_list ov2640_yuv422_regs[] = { ENDMARKER, }; -static const struct regval_list ov2640_rgb565_regs[] = { +static const struct regval_list ov2640_rgb565_be_regs[] = { + { IMAGE_MODE, IMAGE_MODE_RGB565 }, + { 0xd7, 0x03 }, + { RESET, 0x00 }, + { R_BYPASS, R_BYPASS_USE_DSP }, + ENDMARKER, +}; + +static const struct regval_list ov2640_rgb565_le_regs[] = { { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 }, { 0xd7, 0x03 }, { RESET, 0x00 }, @@ -605,7 +624,9 @@ static const struct regval_list ov2640_rgb565_regs[] = { }; static enum v4l2_mbus_pixelcode ov2640_codes[] = { + V4L2_MBUS_FMT_YUYV8_2X8, V4L2_MBUS_FMT_UYVY8_2X8, + V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_MBUS_FMT_RGB565_2X8_LE, }; @@ -787,14 +808,22 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, /* select format */ priv->cfmt_code = 0; switch (code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: + dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__); + selected_cfmt_regs = ov2640_rgb565_be_regs; + break; case V4L2_MBUS_FMT_RGB565_2X8_LE: - dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__); - selected_cfmt_regs = ov2640_rgb565_regs; + dev_dbg(&client->dev, "%s: Selected cfmt RGB565 LE", __func__); + selected_cfmt_regs = ov2640_rgb565_le_regs; + break; + case V4L2_MBUS_FMT_YUYV8_2X8: + dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__); + selected_cfmt_regs = ov2640_yuyv_regs; break; default: case V4L2_MBUS_FMT_UYVY8_2X8: - dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__); - selected_cfmt_regs = ov2640_yuv422_regs; + dev_dbg(&client->dev, "%s: Selected cfmt UYVY", __func__); + selected_cfmt_regs = ov2640_uyvy_regs; } /* reset hardware */ @@ -859,10 +888,12 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd, mf->code = priv->cfmt_code; switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: case V4L2_MBUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: + case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } @@ -879,11 +910,13 @@ static int ov2640_s_fmt(struct v4l2_subdev *sd, switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: case V4L2_MBUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } @@ -896,21 +929,21 @@ static int ov2640_s_fmt(struct v4l2_subdev *sd, static int ov2640_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - const struct ov2640_win_size *win; - /* - * select suitable win + * select suitable win, but don't store it */ - win = ov2640_select_win(&mf->width, &mf->height); + ov2640_select_win(&mf->width, &mf->height); mf->field = V4L2_FIELD_NONE; switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: case V4L2_MBUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 42ae9dc9c57..f434a19b9bc 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -910,18 +910,7 @@ static struct i2c_driver vs6624_driver = { .id_table = vs6624_id, }; -static __init int vs6624_init(void) -{ - return i2c_add_driver(&vs6624_driver); -} - -static __exit void vs6624_exit(void) -{ - i2c_del_driver(&vs6624_driver); -} - -module_init(vs6624_init); -module_exit(vs6624_exit); +module_i2c_driver(vs6624_driver); MODULE_DESCRIPTION("VS6624 sensor driver"); MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); |