diff options
Diffstat (limited to 'drivers/media/video/mxc/capture')
-rw-r--r-- | drivers/media/video/mxc/capture/Kconfig | 18 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/adv7180.c | 67 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/csi_v4l2_capture.c | 12 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/emma_v4l2_capture.c | 17 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/ipu_csi_enc.c | 69 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/ipu_prp_enc.c | 11 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c | 2 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/ipu_still.c | 65 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mt9v111.c | 1085 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mt9v111.h | 8 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mx27_prpsw.c | 4 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mxc_v4l2_capture.c | 565 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mxc_v4l2_capture.h | 6 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/ov3640.c | 87 |
15 files changed, 1379 insertions, 639 deletions
diff --git a/drivers/media/video/mxc/capture/Kconfig b/drivers/media/video/mxc/capture/Kconfig index adab0a886f36..276dfa424feb 100644 --- a/drivers/media/video/mxc/capture/Kconfig +++ b/drivers/media/video/mxc/capture/Kconfig @@ -58,6 +58,22 @@ config MXC_CAMERA_MICRON111 ---help--- If you plan to use the mt9v111 Camera with your MXC system, say Y here. +config MXC_CAMERA_MICRON111_1 + tristate "Micron mt9v111 camera 1 support" + select I2C_MXC + depends on ! VIDEO_MXC_EMMA_CAMERA + depends on MXC_CAMERA_MICRON111 + ---help--- + If you plan to use the mt9v111 Camera 1 with your MXC system, say Y here. + +config MXC_CAMERA_MICRON111_2 + tristate "Micron mt9v111 camera 2 support" + select I2C_MXC + depends on ! VIDEO_MXC_EMMA_CAMERA + depends on MXC_CAMERA_MICRON111 + ---help--- + If you plan to use the mt9v111 Camera 2 with your MXC system, say Y here. + config MXC_CAMERA_OV2640 tristate "OmniVision ov2640 camera support" depends on !VIDEO_MXC_EMMA_CAMERA @@ -72,7 +88,7 @@ config MXC_CAMERA_OV3640 config MXC_TVIN_ADV7180 tristate "Analog Device adv7180 TV Decoder Input support" - depends on MACH_MX35_3DS + depends on (MACH_MX35_3DS || MACH_MX51_3DS) ---help--- If you plan to use the adv7180 video decoder with your MXC system, say Y here. diff --git a/drivers/media/video/mxc/capture/Makefile b/drivers/media/video/mxc/capture/Makefile index 112923c8fc8f..03ff094171bf 100644 --- a/drivers/media/video/mxc/capture/Makefile +++ b/drivers/media/video/mxc/capture/Makefile @@ -35,5 +35,5 @@ obj-$(CONFIG_MXC_CAMERA_OV2640) += ov2640_camera.o ov3640_camera-objs := ov3640.o sensor_clock.o obj-$(CONFIG_MXC_CAMERA_OV3640) += ov3640_camera.o -adv7180_tvin-objs := adv7180.o sensor_clock.o +adv7180_tvin-objs := adv7180.o obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o diff --git a/drivers/media/video/mxc/capture/adv7180.c b/drivers/media/video/mxc/capture/adv7180.c index 1edee763bebc..527a0d1ad9fa 100644 --- a/drivers/media/video/mxc/capture/adv7180.c +++ b/drivers/media/video/mxc/capture/adv7180.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -39,6 +39,7 @@ static struct regulator *dvddio_regulator; static struct regulator *dvdd_regulator; static struct regulator *avdd_regulator; static struct regulator *pvdd_regulator; +static struct mxc_tvin_platform_data *tvin_plat; extern void gpio_sensor_active(void); extern void gpio_sensor_inactive(void); @@ -118,26 +119,26 @@ static video_fmt_t video_fmts[] = { { /*! NTSC */ .v4l2_id = V4L2_STD_NTSC, .name = "NTSC", - .raw_width = 720 - 1, /* SENS_FRM_WIDTH */ - .raw_height = 288 - 1, /* SENS_FRM_HEIGHT */ + .raw_width = 720, /* SENS_FRM_WIDTH */ + .raw_height = 525, /* SENS_FRM_HEIGHT */ .active_width = 720, /* ACT_FRM_WIDTH plus 1 */ - .active_height = (480 / 2), /* ACT_FRM_WIDTH plus 1 */ + .active_height = 480, /* ACT_FRM_WIDTH plus 1 */ }, { /*! (B, G, H, I, N) PAL */ .v4l2_id = V4L2_STD_PAL, .name = "PAL", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 576, }, { /*! Unlocked standard */ .v4l2_id = V4L2_STD_ALL, .name = "Autodetect", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 576, }, }; @@ -246,6 +247,10 @@ static void adv7180_get_std(v4l2_std_id *std) dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_get_std\n"); + /* Make sure power on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + /* Read the AD_RESULT to get the detect output video standard */ tmp = adv7180_read(ADV7180_STATUS_1) & 0x70; @@ -335,6 +340,11 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) if (on && !sensor->on) { gpio_sensor_active(); + + /* Make sure pwoer on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + if (adv7180_write_reg(ADV7180_PWR_MNG, 0) != 0) return -EIO; } else if (!on && sensor->on) { @@ -500,6 +510,10 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n"); + /* Make sure power on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + switch (vc->id) { case V4L2_CID_BRIGHTNESS: dev_dbg(&adv7180_data.i2c_client->dev, @@ -593,6 +607,10 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n"); + /* Make sure power on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + switch (vc->id) { case V4L2_CID_BRIGHTNESS: dev_dbg(&adv7180_data.i2c_client->dev, @@ -803,13 +821,13 @@ static int adv7180_probe(struct i2c_client *client, { int rev_id; int ret = 0; - struct mxc_tvin_platform_data *plat_data = client->dev.platform_data; + tvin_plat = client->dev.platform_data; dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_probe\n"); - if (plat_data->dvddio_reg) { + if (tvin_plat->dvddio_reg) { dvddio_regulator = - regulator_get(&client->dev, plat_data->dvddio_reg); + regulator_get(&client->dev, tvin_plat->dvddio_reg); if (!IS_ERR_VALUE((unsigned long)dvddio_regulator)) { regulator_set_voltage(dvddio_regulator, 3300000, 3300000); if (regulator_enable(dvddio_regulator) != 0) @@ -817,9 +835,9 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->dvdd_reg) { + if (tvin_plat->dvdd_reg) { dvdd_regulator = - regulator_get(&client->dev, plat_data->dvdd_reg); + regulator_get(&client->dev, tvin_plat->dvdd_reg); if (!IS_ERR_VALUE((unsigned long)dvdd_regulator)) { regulator_set_voltage(dvdd_regulator, 1800000, 1800000); if (regulator_enable(dvdd_regulator) != 0) @@ -827,9 +845,9 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->avdd_reg) { + if (tvin_plat->avdd_reg) { avdd_regulator = - regulator_get(&client->dev, plat_data->avdd_reg); + regulator_get(&client->dev, tvin_plat->avdd_reg); if (!IS_ERR_VALUE((unsigned long)avdd_regulator)) { regulator_set_voltage(avdd_regulator, 1800000, 1800000); if (regulator_enable(avdd_regulator) != 0) @@ -837,9 +855,9 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->pvdd_reg) { + if (tvin_plat->pvdd_reg) { pvdd_regulator = - regulator_get(&client->dev, plat_data->pvdd_reg); + regulator_get(&client->dev, tvin_plat->pvdd_reg); if (!IS_ERR_VALUE((unsigned long)pvdd_regulator)) { regulator_set_voltage(pvdd_regulator, 1800000, 1800000); if (regulator_enable(pvdd_regulator) != 0) @@ -847,11 +865,12 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->reset) - plat_data->reset(); - if (plat_data->pwdn) - plat_data->pwdn(1); + if (tvin_plat->reset) + tvin_plat->reset(); + + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); msleep(1); @@ -913,7 +932,7 @@ static int adv7180_detach(struct i2c_client *client) __func__, IF_NAME, client->addr << 1, client->adapter->name); if (plat_data->pwdn) - plat_data->pwdn(0); + plat_data->pwdn(1); if (dvddio_regulator) { regulator_disable(dvddio_regulator); diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c index 9bddc3692996..cf224e0673f0 100644 --- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -789,15 +789,15 @@ static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count, (cam->v2f.fmt. pix.sizeimage), &cam-> - still_buf, + still_buf[0], GFP_DMA | GFP_KERNEL); if (cam->still_buf_vaddr == NULL) { pr_err("alloc dma memory failed\n"); return -ENOMEM; } cam->still_counter = 0; - __raw_writel(cam->still_buf, CSI_CSIDMASA_FB2); - __raw_writel(cam->still_buf, CSI_CSIDMASA_FB1); + __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB2); + __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB1); __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, CSI_CSICR3); __raw_writel(__raw_readl(CSI_CSISR), CSI_CSISR); @@ -813,8 +813,8 @@ static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count, if (cam->still_buf_vaddr != NULL) { dma_free_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), - cam->still_buf_vaddr, cam->still_buf); - cam->still_buf = 0; + cam->still_buf_vaddr, cam->still_buf[0]); + cam->still_buf[0] = 0; cam->still_buf_vaddr = NULL; } diff --git a/drivers/media/video/mxc/capture/emma_v4l2_capture.c b/drivers/media/video/mxc/capture/emma_v4l2_capture.c index 9cb08b26f1cd..170807716ec6 100644 --- a/drivers/media/video/mxc/capture/emma_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/emma_v4l2_capture.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -858,7 +858,7 @@ static void mxc_csi_dma_chaining(void *data) /* Config DMA */ memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t)); - dma_request.dst_addr = cam->still_buf + dma_request.dst_addr = cam->still_buf[0] + (chained % max_dma) * CSI_DMA_LENGTH; dma_request.src_addr = (dma_addr_t) CSI_CSIRXFIFO_PHYADDR; dma_request.num_of_bytes = count; @@ -1040,7 +1040,7 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) cam->still_buf_vaddr = dma_alloc_coherent(0, PAGE_ALIGN(CSI_MEM_SIZE), - &cam->still_buf, + &cam->still_buf[0], GFP_DMA | GFP_KERNEL); if (!cam->still_buf_vaddr) { @@ -1120,8 +1120,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) exit1: dma_free_coherent(0, PAGE_ALIGN(CSI_MEM_SIZE), - cam->still_buf_vaddr, cam->still_buf); - cam->still_buf = 0; + cam->still_buf_vaddr, cam->still_buf[0]); + cam->still_buf[0] = 0; exit0: up(&cam->busy_lock); @@ -1160,7 +1160,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) v_address = dma_alloc_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), - &cam->still_buf, GFP_DMA | GFP_KERNEL); + &cam->still_buf[0], + GFP_DMA | GFP_KERNEL); if (!v_address) { pr_info("mxc_v4l_read failed at allocate still_buf\n"); @@ -1194,8 +1195,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) exit1: dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address, - cam->still_buf); - cam->still_buf = 0; + cam->still_buf[0]); + cam->still_buf[0] = 0; exit0: up(&cam->busy_lock); diff --git a/drivers/media/video/mxc/capture/ipu_csi_enc.c b/drivers/media/video/mxc/capture/ipu_csi_enc.c index fd3f0c132c14..0b87282551ff 100644 --- a/drivers/media/video/mxc/capture/ipu_csi_enc.c +++ b/drivers/media/video/mxc/capture/ipu_csi_enc.c @@ -25,6 +25,7 @@ #include "ipu_prp_sw.h" #ifdef CAMERA_DBG + extern void ipu_dump_registers(void); #define CAMERA_TRACE(x) (printk)x #else #define CAMERA_TRACE(x) @@ -66,6 +67,7 @@ static int csi_enc_setup(cam_data *cam) u32 pixel_fmt; int err = 0; dma_addr_t dummy = cam->dummy_frame.buffer.m.offset; + ipu_channel_t channel; CAMERA_TRACE("In csi_enc_setup\n"); if (!cam) { @@ -101,13 +103,18 @@ static int csi_enc_setup(cam_data *cam) ipu_csi_enable_mclk_if(CSI_MCLK_ENC, cam->csi, true, true); - err = ipu_init_channel(CSI_MEM, ¶ms); + if (cam->csi == 0) + channel = CSI_MEM0; + else + channel = CSI_MEM1; + + err = ipu_init_channel(channel, ¶ms); if (err != 0) { printk(KERN_ERR "ipu_init_channel %d\n", err); return err; } - err = ipu_init_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + err = ipu_init_channel_buffer(channel, IPU_OUTPUT_BUFFER, pixel_fmt, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height, cam->v2f.fmt.pix.width, IPU_ROTATE_NONE, @@ -115,12 +122,12 @@ static int csi_enc_setup(cam_data *cam) cam->offset.u_offset, cam->offset.v_offset); if (err != 0) { - printk(KERN_ERR "CSI_MEM output buffer\n"); + printk(KERN_ERR "CSI_MEM%d output buffer\n",cam->csi); return err; } - err = ipu_enable_channel(CSI_MEM); + err = ipu_enable_channel(channel); if (err < 0) { - printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); + printk(KERN_ERR "ipu_enable_channel CSI_MEM%d\n",cam->csi); return err; } @@ -135,24 +142,34 @@ static int csi_enc_setup(cam_data *cam) * * @return status */ -static int csi_enc_eba_update(dma_addr_t eba, int *buffer_num) +static int csi_enc_eba_update(int csi, dma_addr_t eba, int *buffer_num) { int err = 0; + ipu_channel_t channel; + + if (csi == 0) + channel = CSI_MEM0; + else + channel = CSI_MEM1; - pr_debug("eba %x\n", eba); - err = ipu_update_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + err = ipu_update_channel_buffer(channel, IPU_OUTPUT_BUFFER, *buffer_num, eba); + if (err != 0) { - ipu_clear_buffer_ready(CSI_MEM, IPU_OUTPUT_BUFFER, + ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, *buffer_num); printk(KERN_ERR "err %d buffer_num %d\n", err, *buffer_num); return err; } - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); + ipu_select_buffer(channel, IPU_OUTPUT_BUFFER, *buffer_num); *buffer_num = (*buffer_num == 0) ? 1 : 0; +#ifdef CAMERA_DBG + ipu_dump_registers (); +#endif + return 0; } @@ -166,6 +183,7 @@ static int csi_enc_enabling_tasks(void *private) { cam_data *cam = (cam_data *) private; int err = 0; + int ipu_irq_csi_out_eof; CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n"); cam->dummy_frame.vaddress = dma_alloc_coherent(0, @@ -182,11 +200,16 @@ static int csi_enc_enabling_tasks(void *private) PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; - ipu_clear_irq(IPU_IRQ_CSI0_OUT_EOF); - err = ipu_request_irq(IPU_IRQ_CSI0_OUT_EOF, - csi_enc_callback, 0, "Mxc Camera", cam); + if (cam->csi == 0) + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + else + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + ipu_clear_irq(ipu_irq_csi_out_eof); + err = ipu_request_irq(ipu_irq_csi_out_eof, + csi_enc_callback, 0, "Mxc Camera", cam); + if (err != 0) { - printk(KERN_ERR "Error registering rot irq\n"); + printk(KERN_ERR "Error registering eot irq for csi %d\n",cam->csi); return err; } @@ -209,12 +232,24 @@ static int csi_enc_disabling_tasks(void *private) { cam_data *cam = (cam_data *) private; int err = 0; + ipu_channel_t channel; + int ipu_irq_csi_out_eof; - ipu_free_irq(IPU_IRQ_CSI0_OUT_EOF, cam); + if (cam->csi == 0) + { + channel = CSI_MEM0; + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + } + else + { + channel = CSI_MEM1; + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + } - err = ipu_disable_channel(CSI_MEM, true); + ipu_free_irq(ipu_irq_csi_out_eof, cam); + err = ipu_disable_channel(channel, true); - ipu_uninit_channel(CSI_MEM); + ipu_uninit_channel(channel); if (cam->dummy_frame.vaddress != 0) { dma_free_coherent(0, cam->dummy_frame.buffer.length, diff --git a/drivers/media/video/mxc/capture/ipu_prp_enc.c b/drivers/media/video/mxc/capture/ipu_prp_enc.c index 4b5426cb887d..0df8050ad7de 100644 --- a/drivers/media/video/mxc/capture/ipu_prp_enc.c +++ b/drivers/media/video/mxc/capture/ipu_prp_enc.c @@ -19,12 +19,14 @@ * @ingroup IPU */ +#include <linux/types.h> #include <linux/dma-mapping.h> #include <linux/ipu.h> #include "mxc_v4l2_capture.h" #include "ipu_prp_sw.h" #ifdef CAMERA_DBG + extern void ipu_dump_registers(void); #define CAMERA_TRACE(x) (printk)x #else #define CAMERA_TRACE(x) @@ -266,11 +268,10 @@ static int prp_enc_setup(cam_data * cam) * * @return status */ -static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num) +static int prp_enc_eba_update(int csi, dma_addr_t eba, int *buffer_num) { int err = 0; - pr_debug("eba %x\n", eba); if (grotation >= IPU_ROTATE_90_RIGHT) { err = ipu_update_channel_buffer(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, @@ -294,6 +295,11 @@ static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num) } *buffer_num = (*buffer_num == 0) ? 1 : 0; + +#ifdef CAMERA_DBG + ipu_dump_registers (); +#endif + return 0; } @@ -350,7 +356,6 @@ static int prp_enc_disabling_tasks(void *private) if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ipu_unlink_channels(CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM); } - err = ipu_disable_channel(CSI_PRP_ENC_MEM, true); if (cam->rotation >= IPU_ROTATE_90_RIGHT) { err |= ipu_disable_channel(MEM_ROT_ENC_MEM, true); diff --git a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c index 7f0984c42950..9f8078d558b0 100644 --- a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c +++ b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c @@ -182,6 +182,7 @@ static int prpvf_start(void *private) printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n"); goto out_3; } + err = ipu_init_channel(MEM_ROT_VF_MEM, NULL); if (err != 0) { printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n"); @@ -200,6 +201,7 @@ static int prpvf_start(void *private) } if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { + err = ipu_init_channel_buffer(MEM_ROT_VF_MEM, IPU_OUTPUT_BUFFER, format, vf.csi_prp_vf_mem.out_height, diff --git a/drivers/media/video/mxc/capture/ipu_still.c b/drivers/media/video/mxc/capture/ipu_still.c index 348bf2b9b564..22cf3f51e1cb 100644 --- a/drivers/media/video/mxc/capture/ipu_still.c +++ b/drivers/media/video/mxc/capture/ipu_still.c @@ -26,6 +26,9 @@ #include "ipu_prp_sw.h" static int callback_eof_flag; +#ifndef CONFIG_MXC_IPU_V1 +static int buffer_num; +#endif #ifdef CONFIG_MXC_IPU_V1 static int callback_flag; @@ -42,10 +45,10 @@ static int callback_flag; */ static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id) { - if (callback_flag == 2) { - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + callback_flag%2 ? 1 : 0); + if (callback_flag == 0) ipu_enable_channel(CSI_MEM); - } callback_flag++; return IRQ_HANDLED; @@ -65,9 +68,12 @@ static irqreturn_t prp_still_callback(int irq, void *dev_id) cam_data *cam = (cam_data *) dev_id; callback_eof_flag++; - if (callback_eof_flag < 5) - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0); - else { + if (callback_eof_flag < 5) { +#ifndef CONFIG_MXC_IPU_V1 + buffer_num = (buffer_num == 0) ? 1 : 0; + ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, buffer_num); +#endif + } else { cam->still_counter++; wake_up_interruptible(&cam->still_queue); } @@ -87,6 +93,8 @@ static int prp_still_start(void *private) u32 pixel_fmt; int err; ipu_channel_params_t params; + ipu_channel_t channel; + int ipu_irq_csi_out_eof; if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) pixel_fmt = IPU_PIX_FMT_YUV420P; @@ -113,20 +121,32 @@ static int prp_still_start(void *private) ipu_csi_enable_mclk_if(CSI_MCLK_RAW, cam->csi, true, true); + if (cam->csi == 0) { + channel = CSI_MEM0; + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + } + else { + channel = CSI_MEM1; + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + } + memset(¶ms, 0, sizeof(params)); - err = ipu_init_channel(CSI_MEM, ¶ms); + params.csi_mem.csi = cam->csi; + err = ipu_init_channel(channel, ¶ms); if (err != 0) return err; - err = ipu_init_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + err = ipu_init_channel_buffer(channel, IPU_OUTPUT_BUFFER, pixel_fmt, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height, cam->v2f.fmt.pix.width, IPU_ROTATE_NONE, - cam->still_buf, 0, 0, 0); + cam->still_buf[0], cam->still_buf[1], + 0, 0); if (err != 0) return err; #ifdef CONFIG_MXC_IPU_V1 + ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF); err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback, 0, "Mxc Camera", cam); if (err != 0) { @@ -135,6 +155,7 @@ static int prp_still_start(void *private) } callback_flag = 0; callback_eof_flag = 0; + ipu_clear_irq(IPU_IRQ_SENSOR_EOF); err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback, 0, "Mxc Camera", NULL); if (err != 0) { @@ -142,8 +163,9 @@ static int prp_still_start(void *private) return err; } #else - ipu_clear_irq(IPU_IRQ_CSI0_OUT_EOF); - err = ipu_request_irq(IPU_IRQ_CSI0_OUT_EOF, prp_still_callback, + + ipu_clear_irq(ipu_irq_csi_out_eof); + err = ipu_request_irq(ipu_irq_csi_out_eof, prp_still_callback, 0, "Mxc Camera", cam); if (err != 0) { printk(KERN_ERR "Error registering irq.\n"); @@ -151,9 +173,9 @@ static int prp_still_start(void *private) } callback_eof_flag = 0; + ipu_select_buffer(channel, IPU_OUTPUT_BUFFER, 0); + ipu_enable_channel(channel); - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0); - ipu_enable_channel(CSI_MEM); ipu_enable_csi(cam->csi); #endif @@ -170,17 +192,28 @@ static int prp_still_stop(void *private) { cam_data *cam = (cam_data *) private; int err = 0; + ipu_channel_t channel; + int ipu_irq_csi_out_eof; + + if (cam->csi == 0) { + channel = CSI_MEM0; + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + } + else { + channel = CSI_MEM1; + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + } #ifdef CONFIG_MXC_IPU_V1 ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL); ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam); #else - ipu_free_irq(IPU_IRQ_CSI0_OUT_EOF, cam); + ipu_free_irq(ipu_irq_csi_out_eof, cam); #endif ipu_disable_csi(cam->csi); - ipu_disable_channel(CSI_MEM, true); - ipu_uninit_channel(CSI_MEM); + ipu_disable_channel(channel, true); + ipu_uninit_channel(channel); ipu_csi_enable_mclk_if(CSI_MCLK_RAW, cam->csi, false, false); return err; diff --git a/drivers/media/video/mxc/capture/mt9v111.c b/drivers/media/video/mxc/capture/mt9v111.c index c95a20683924..dfdd455db3dd 100644 --- a/drivers/media/video/mxc/capture/mt9v111.c +++ b/drivers/media/video/mxc/capture/mt9v111.c @@ -18,6 +18,9 @@ * * @ingroup Camera */ + +//#define MT9V111_DEBUG + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -40,7 +43,6 @@ static mt9v111_conf mt9v111_device; /*! * Holds the current frame rate. */ -static int reset_frame_rate = MT9V111_FRAME_RATE; struct sensor { const struct mt9v111_platform_data *platform_data; @@ -49,33 +51,45 @@ struct sensor { struct v4l2_pix_format pix; struct v4l2_captureparm streamcap; bool on; + bool used; /* control settings */ int brightness; - int hue; - int contrast; int saturation; - int red; - int green; - int blue; + int sharpness; + int gain; int ae_mode; -} mt9v111_data; - -extern void gpio_sensor_active(void); -extern void gpio_sensor_inactive(void); +}; static int mt9v111_probe(struct i2c_client *client, const struct i2c_device_id *id); static int mt9v111_remove(struct i2c_client *client); static const struct i2c_device_id mt9v111_id[] = { - {"mt9v111", 0}, + {"mt9v111_1", 2}, + {"mt9v111_2", 3}, {}, }; +struct sensor mt9v111_data[ARRAY_SIZE(mt9v111_id)-1]; + MODULE_DEVICE_TABLE(i2c, mt9v111_id); +static int mt9v111_suspend(struct i2c_client *client, pm_message_t mesg) +{ + pr_debug("In mt9v111_suspend\n"); + + return 0; +} + +static int mt9v111_resume(struct i2c_client *client) +{ + pr_debug("In mt9v111_resume\n"); + + return 0; +} + static struct i2c_driver mt9v111_i2c_driver = { .driver = { .owner = THIS_MODULE, @@ -84,37 +98,52 @@ static struct i2c_driver mt9v111_i2c_driver = { .probe = mt9v111_probe, .remove = mt9v111_remove, .id_table = mt9v111_id, -/* To add power management add .suspend and .resume functions */ + .suspend = mt9v111_suspend, + .resume = mt9v111_resume, }; /* * Function definitions */ -#ifdef MT9V111_DEBUG -static inline int mt9v111_read_reg(u8 reg) +static int mt9v111_id_from_name ( const char * name ) +{ + int id = -1; + + if( name == NULL || ( strlen(name) < strlen("mt9v111_n") ) ) + return -1; + + id = (int)simple_strtol(name+strlen("mt9v111_"),NULL,0) - 1; + if( id >= ARRAY_SIZE(mt9v111_id) ) { + printk("Invalid sensor index %d for %s\n",id,name); + return -1; + } + + return id; +} + +static inline int mt9v111_read_reg(int sensorid , u8 reg) { - int val = i2c_smbus_read_word_data(mt9v111_data.i2c_client, reg); + int val = i2c_smbus_read_word_data(mt9v111_data[sensorid].i2c_client, reg); if (val != -1) val = cpu_to_be16(val); return val; } -#endif /*! * Writes to the register via I2C. */ -static inline int mt9v111_write_reg(u8 reg, u16 val) +static inline int mt9v111_write_reg(int sensorid , u8 reg, u16 val) { - pr_debug("In mt9v111_write_reg (0x%x, 0x%x)\n", reg, val); + pr_debug("[%d] In mt9v111_write_reg (0x%x, 0x%x)\n", sensorid , reg, val); pr_debug(" write reg %x val %x.\n", reg, val); - return i2c_smbus_write_word_data(mt9v111_data.i2c_client, + return i2c_smbus_write_word_data(mt9v111_data[sensorid].i2c_client, reg, cpu_to_be16(val)); } /*! - * Initialize mt9v111_sensor_lib + * Initialize mt9v111_sensor_lib_datasheet * Libarary for Sensor configuration through I2C * * @param coreReg Core Registers @@ -122,7 +151,7 @@ static inline int mt9v111_write_reg(u8 reg, u16 val) * * @return status */ -static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg) +static u8 mt9v111_sensor_lib_datasheet(int sensorid , mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg) { u8 reg; u16 data; @@ -130,200 +159,103 @@ static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg) pr_debug("In mt9v111_sensor_lib\n"); + /* IFP R51(0x33)=5137,R57(0x39)=290,R59(0x3B)=1068,R62(0x3E)=4095,R89(0x59)=504,R90(0x5A)=605,R92(0x5C)=8222,R93(0x5D)=10021,R100(0x64)=4477 */ + /* * setup to IFP registers */ reg = MT9V111I_ADDR_SPACE_SEL; data = ifpReg->addrSpaceSel; - mt9v111_write_reg(reg, data); - - /* Operation Mode Control */ - reg = MT9V111I_MODE_CONTROL; - data = ifpReg->modeControl; - mt9v111_write_reg(reg, data); - - /* Output format */ - reg = MT9V111I_FORMAT_CONTROL; - data = ifpReg->formatControl; /* Set bit 12 */ - mt9v111_write_reg(reg, data); - - /* AE limit 4 */ - reg = MT9V111I_SHUTTER_WIDTH_LIMIT_AE; - data = ifpReg->gainLimitAE; - mt9v111_write_reg(reg, data); - - reg = MT9V111I_OUTPUT_FORMAT_CTRL2; - data = ifpReg->outputFormatCtrl2; - mt9v111_write_reg(reg, data); - - reg = MT9V111I_AE_SPEED; - data = ifpReg->AESpeed; - mt9v111_write_reg(reg, data); - - /* output image size */ - reg = MT9V111i_H_PAN; - data = 0x8000 | ifpReg->HPan; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_H_ZOOM; - data = 0x8000 | ifpReg->HZoom; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_H_SIZE; - data = 0x8000 | ifpReg->HSize; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_V_PAN; - data = 0x8000 | ifpReg->VPan; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); - reg = MT9V111i_V_ZOOM; - data = 0x8000 | ifpReg->VZoom; - mt9v111_write_reg(reg, data); + reg = MT9V111I_LIMIT_SHARP_SATU_CTRL; + data = ifpReg->limitSharpSatuCtrl; + mt9v111_write_reg(sensorid,reg, data); - reg = MT9V111i_V_SIZE; - data = 0x8000 | ifpReg->VSize; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_H_PAN; - data = ~0x8000 & ifpReg->HPan; - mt9v111_write_reg(reg, data); -#if 0 reg = MT9V111I_UPPER_SHUTTER_DELAY_LIM; data = ifpReg->upperShutterDelayLi; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_IPF_BLACK_LEVEL_SUB; + data = ifpReg->ipfBlackLevelSub; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_GAIN_THRE_CCAM_ADJ; + data = ifpReg->agimnThreCamAdj; + mt9v111_write_reg(sensorid,reg, data); reg = MT9V111I_SHUTTER_60; data = ifpReg->shutter_width_60; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_AUTO_EXPOSURE_17; + data = ifpReg->auto_exposure_17; + mt9v111_write_reg(sensorid,reg, data); reg = MT9V111I_SEARCH_FLICK_60; data = ifpReg->search_flicker_60; - mt9v111_write_reg(reg, data); -#endif + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_RESERVED93; + data = ifpReg->reserved93; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_RESERVED100; + data = ifpReg->reserved100; + mt9v111_write_reg(sensorid,reg, data); /* * setup to sensor core registers */ reg = MT9V111I_ADDR_SPACE_SEL; data = coreReg->addressSelect; - mt9v111_write_reg(reg, data); - - /* enable changes and put the Sync bit on */ - reg = MT9V111S_OUTPUT_CTRL; - data = MT9V111S_OUTCTRL_SYNC | MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); - /* min PIXCLK - Default */ - reg = MT9V111S_PIXEL_CLOCK_SPEED; - data = coreReg->pixelClockSpeed; - mt9v111_write_reg(reg, data); + /* Core R5=46, R7[4]=0 (DEFAULT) ,R33=58369*/ - /* Setup image flipping / Dark rows / row/column skip */ - reg = MT9V111S_READ_MODE; - data = coreReg->readMode; - mt9v111_write_reg(reg, data); - - /* zoom 0 */ - reg = MT9V111S_DIGITAL_ZOOM; - data = coreReg->digitalZoom; - mt9v111_write_reg(reg, data); - - /* min H-blank */ reg = MT9V111S_HOR_BLANKING; data = coreReg->horizontalBlanking; - mt9v111_write_reg(reg, data); - - /* min V-blank */ - reg = MT9V111S_VER_BLANKING; - data = coreReg->verticalBlanking; - mt9v111_write_reg(reg, data); - - reg = MT9V111S_SHUTTER_WIDTH; - data = coreReg->shutterWidth; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); - reg = MT9V111S_SHUTTER_DELAY; - data = ifpReg->upperShutterDelayLi; - mt9v111_write_reg(reg, data); - - /* changes become effective */ - reg = MT9V111S_OUTPUT_CTRL; - data = MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000; - mt9v111_write_reg(reg, data); + reg = MT9V111S_RESERVED33; + data = coreReg->reserved33; + mt9v111_write_reg(sensorid,reg, data); return error; } -/*! - * MT9V111 frame rate calculate - * - * @param frame_rate int * - * @param mclk int - * @return None - */ -static void mt9v111_rate_cal(int *frame_rate, int mclk) +void mt9v111_config_datasheet(void) { - int num_clock_per_row; - int max_rate = 0; + pr_debug("In mt9v111_config_datasheet\n"); - pr_debug("In mt9v111_rate_cal\n"); + mt9v111_device.coreReg->addressSelect = MT9V111I_SEL_SCA; - num_clock_per_row = (MT9V111_MAX_WIDTH + 114 + MT9V111_HORZBLANK_MIN) - * 2; - max_rate = mclk / (num_clock_per_row * - (MT9V111_MAX_HEIGHT + MT9V111_VERTBLANK_DEFAULT)); + /* MT9V111I_ADDR_SPACE_SEL */ + mt9v111_device.ifpReg->addrSpaceSel = MT9V111I_SEL_IFP; - if ((*frame_rate > max_rate) || (*frame_rate == 0)) { - *frame_rate = max_rate; - } + /* Recommended values for 30fps @ 27MHz from datasheet*/ - mt9v111_device.coreReg->verticalBlanking - = mclk / (*frame_rate * num_clock_per_row) - MT9V111_MAX_HEIGHT; + /* Core R5=132, R6=10 , R7[4]=0 (DEFAULT) ,R33=58369*/ - reset_frame_rate = *frame_rate; -} + mt9v111_device.coreReg->horizontalBlanking = 132; + mt9v111_device.coreReg->verticalBlanking = 10; + mt9v111_device.coreReg->reserved33 = 58369; -/*! - * MT9V111 sensor configuration - */ -void mt9v111_config(void) -{ - pr_debug("In mt9v111_config\n"); + /* IFP R51(0x33)=5137,R57(0x39)=290,R59(0x3B)=1068,R62(0x3E)=4095,R89(0x59)=504,R90(0x5A)=605,R92(0x5C)=8222,R93(0x5D)=10021,R100(0x64)=4477 */ - mt9v111_device.coreReg->addressSelect = MT9V111I_SEL_SCA; - mt9v111_device.ifpReg->addrSpaceSel = MT9V111I_SEL_IFP; + mt9v111_device.ifpReg->limitSharpSatuCtrl = 5137; + mt9v111_device.ifpReg->upperShutterDelayLi = 290; + mt9v111_device.ifpReg->ipfBlackLevelSub = 1068; + mt9v111_device.ifpReg->agimnThreCamAdj = 4095; - mt9v111_device.coreReg->windowHeight = MT9V111_WINHEIGHT; - mt9v111_device.coreReg->windowWidth = MT9V111_WINWIDTH; - mt9v111_device.coreReg->zoomColStart = 0; - mt9v111_device.coreReg->zomRowStart = 0; - mt9v111_device.coreReg->digitalZoom = 0x0; - - mt9v111_device.coreReg->verticalBlanking = MT9V111_VERTBLANK_DEFAULT; - mt9v111_device.coreReg->horizontalBlanking = MT9V111_HORZBLANK_MIN; - mt9v111_device.coreReg->pixelClockSpeed = 0; - mt9v111_device.coreReg->readMode = 0xd0a1; - - mt9v111_device.ifpReg->outputFormatCtrl2 = 0; - mt9v111_device.ifpReg->gainLimitAE = 0x300; - mt9v111_device.ifpReg->AESpeed = 0x80; - - /* here is the default value */ - mt9v111_device.ifpReg->formatControl = 0xc800; - mt9v111_device.ifpReg->modeControl = 0x708e; - mt9v111_device.ifpReg->awbSpeed = 0x4514; - mt9v111_device.coreReg->shutterWidth = 0xf8; - - /* output size */ - mt9v111_device.ifpReg->HPan = 0; - mt9v111_device.ifpReg->HZoom = MT9V111_MAX_WIDTH; - mt9v111_device.ifpReg->HSize = MT9V111_MAX_WIDTH; - mt9v111_device.ifpReg->VPan = 0; - mt9v111_device.ifpReg->VZoom = MT9V111_MAX_HEIGHT; - mt9v111_device.ifpReg->VSize = MT9V111_MAX_HEIGHT; + mt9v111_device.ifpReg->shutter_width_60 = 504; + mt9v111_device.ifpReg->auto_exposure_17 = 605; + mt9v111_device.ifpReg->search_flicker_60 = 8222; + mt9v111_device.ifpReg->reserved93 = 10021; + mt9v111_device.ifpReg->reserved100 = 4477; } + /*! * mt9v111 sensor set saturtionn * @@ -331,7 +263,7 @@ void mt9v111_config(void) * @return Error code of 0. */ -static int mt9v111_set_saturation(int saturation) +static int mt9v111_set_saturation(int sensorid , int saturation) { u8 reg; u16 data; @@ -357,6 +289,9 @@ static int mt9v111_set_saturation(int saturation) case 25: mt9v111_device.ifpReg->awbSpeed = 0x6514; break; + case 0: + mt9v111_device.ifpReg->awbSpeed = 0x7514; + break; default: mt9v111_device.ifpReg->awbSpeed = 0x4514; break; @@ -364,12 +299,348 @@ static int mt9v111_set_saturation(int saturation) reg = MT9V111I_ADDR_SPACE_SEL; data = mt9v111_device.ifpReg->addrSpaceSel; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); /* Operation Mode Control */ reg = MT9V111I_AWB_SPEED; data = mt9v111_device.ifpReg->awbSpeed; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +#if 0 +/*! + * mt9v111 sensor set digital zoom + * + * @param on/off int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalzoom(int sensorid , unsigned int on) +{ + u8 reg; + u16 data; + pr_debug("In mt9v111_set_digitalzoom(%d)\n",on); + + if( on > 1 ) + return -1; + + mt9v111_device.coreReg->digitalZoom = on; + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.coreReg->addressSelect; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111S_DIGITAL_ZOOM; + data = mt9v111_device.coreReg->digitalZoom; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital pan + * + * @param pan_level int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalpan (int sensorid , int pan_level) +{ + u8 reg; + u16 data; + pr_debug("In mt9v111_set_digitalpan(%d)\n", + pan_level); + + mt9v111_device.ifpReg->HPan = 8; + if (pan_level & 0xFFFF0000) { + pan_level = (0xFFFFFFFF - pan_level); + pan_level = pan_level / 0x14; + mt9v111_device.ifpReg->HPan = + mt9v111_device.ifpReg->HPan - (pan_level & 0x3FF); + } else { + pan_level = pan_level / 0x14; + mt9v111_device.ifpReg->HPan = + mt9v111_device.ifpReg->HPan + (pan_level - 1); + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111i_H_PAN; + data = mt9v111_device.ifpReg->HPan; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital tilt + * + * @param tilt_level int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitaltilt (int sensorid , int tilt_level) +{ + u8 reg; + u16 data; + pr_debug("In mt9v111_set_digitaltilt(%d)\n", + tilt_level); + + mt9v111_device.ifpReg->VPan = 8; + if( tilt_level & 0xFFFF0000 ) { + tilt_level = (0xFFFFFFFF - tilt_level); + tilt_level = tilt_level / 0x14; + mt9v111_device.ifpReg->VPan = mt9v111_device.ifpReg->VPan - (tilt_level & 0x3FF); + } + else { + tilt_level = tilt_level / 0x14; + mt9v111_device.ifpReg->VPan = mt9v111_device.ifpReg->VPan + (tilt_level - 1); + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111i_V_PAN; + data = mt9v111_device.ifpReg->VPan; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set output resolution + * + * @param resolution res + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_outputresolution(int sensorid , MT9V111_OutputResolution res) +{ + u8 reg; + u16 data; + int zoom = 0; + + pr_debug("In mt9v111_set_outputresolution(%d)\n",res); + + switch (res) { + case MT9V111_OutputResolution_VGA: + /* 640x480 */ + mt9v111_device.ifpReg->HSize = 0x0280; + mt9v111_device.ifpReg->VSize = 0x01E0; + break; + + case MT9V111_OutputResolution_QVGA: + /* 320x240 */ + mt9v111_device.ifpReg->HSize = 0x0140; + mt9v111_device.ifpReg->VSize = 0x00F0; + break; + + case MT9V111_OutputResolution_CIF: + /* 352x288 */ + mt9v111_device.ifpReg->HSize = 0x0160; + mt9v111_device.ifpReg->VSize = 0x0120; + mt9v111_device.ifpReg->HZoom = 0x0160; + mt9v111_device.ifpReg->VZoom = 0x0120; + zoom = 1; + break; + + case MT9V111_OutputResolution_QCIF: + /* 176X220 */ + mt9v111_device.ifpReg->HSize = 0x00B0; + mt9v111_device.ifpReg->VSize = 0x0090; + mt9v111_device.ifpReg->HZoom = 0x00B0; + mt9v111_device.ifpReg->VZoom = 0x0090; + zoom = 1; + break; + + case MT9V111_OutputResolution_QQVGA: + /* 2048*1536 */ + mt9v111_device.ifpReg->HSize = 0x00A0; + mt9v111_device.ifpReg->VSize = 0x0078; + mt9v111_device.ifpReg->HZoom = 0x00A0; + mt9v111_device.ifpReg->VZoom = 0x0078; + zoom = 1; + break; + + case MT9V111_OutputResolution_SXGA: + /* 1280x1024 */ + break; + + default: + break; + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111i_V_SIZE; + data = mt9v111_device.ifpReg->VSize; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111i_H_SIZE; + data = mt9v111_device.ifpReg->HSize; + mt9v111_write_reg(sensorid,reg, data); + + if ( zoom ) { + reg = MT9V111i_V_ZOOM; + data = mt9v111_device.ifpReg->VZoom; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111i_H_ZOOM; + data = mt9v111_device.ifpReg->HZoom; + mt9v111_write_reg(sensorid,reg, data); + } + + return 0; +} + +/*! + * mt9v111 sensor set digital flash + * + * @param flash_level int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalflash (int sensorid , int flash_level) +{ + u8 reg; + u16 data = mt9v111_read_reg(sensorid,MT9V111i_FLASH_CTRL); + pr_debug("In mt9v111_set_digitalflash(%d)\n", + flash_level); + + if(flash_level) { + data &= (0xFF00); + data |= ((flash_level & 0x00FF) | (1<<13)); + } + else { + data &= ~(1<<13); + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111i_FLASH_CTRL; + mt9v111_device.ifpReg->flashCtrl = data; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital monochrome + * + * @param on int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalmonochrome (int sensorid , int on) +{ + u8 reg; + u16 data = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL); + pr_debug("In mt9v111_set_digitalmonochrome(%d)\n", + on); + + /* clear the monochrome bit field */ + data &= ~(1<<5); + + /* enable or disable monochrome mode */ + if( on ) + data |= (0<<5); + else + data |= (1<<5); + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111I_FORMAT_CONTROL; + mt9v111_device.ifpReg->formatControl = data; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} +#endif + +/*! + * mt9v111 sensor set digital sharpness + * + * @param value int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalsharpness (int sensorid , int value) +{ + u8 reg; + u16 data ; + + pr_debug("In mt9v111_set_digitalsharpness(%d)\n",value); + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + data = mt9v111_read_reg(sensorid,MT9V111I_APERTURE_GAIN); + + /* erase current and remove auto reduce sharpness in low light */ + data &= ~(0x000F); + data |= (value & (0x000F)); + if( data > (0x000F) ) + return -1; + + /* Operation Mode Control */ + reg = MT9V111I_APERTURE_GAIN; + mt9v111_device.ifpReg->apertureGain = data; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital brightness + * + * @param value int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalbrightness (int sensorid , int value) +{ + u8 reg; + u16 data; + u32 max_brightness, min_brightness; + + data = mt9v111_read_reg(sensorid,MT9V111I_CLIP_LIMIT_OUTPUT_LUMI); + max_brightness = data >> 8; + min_brightness = (u8)data; + + if( value > max_brightness ) + value = max_brightness; + else if( value < min_brightness ) + value = min_brightness; + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + data = mt9v111_read_reg(sensorid,MT9V111I_AE_PRECISION_TARGET); + data &= 0xFF00; /* Clear target luminance */ + data |= ((u8)value ); + + /* Operation Mode Control */ + reg = MT9V111I_AE_PRECISION_TARGET; + mt9v111_device.ifpReg->AEPrecisionTarget = data; + mt9v111_write_reg(sensorid,reg, data); return 0; } @@ -380,7 +651,7 @@ static int mt9v111_set_saturation(int saturation) * @param ae_mode int * @return Error code of 0 (no Error) */ -static int mt9v111_set_ae_mode(int ae_mode) +static int mt9v111_set_ae_mode(int sensorid , int ae_mode) { u8 reg; u16 data; @@ -408,19 +679,20 @@ static int mt9v111_set_ae_mode(int ae_mode) /* V4L2_EXPOSURE_MANUAL = 1 needs register setting of 0x308E */ mt9v111_device.ifpReg->modeControl &= 0x3fff; mt9v111_device.ifpReg->modeControl |= (ae_mode & 0x03) << 14; - mt9v111_data.ae_mode = ae_mode; + mt9v111_data[sensorid].ae_mode = ae_mode; reg = MT9V111I_ADDR_SPACE_SEL; data = mt9v111_device.ifpReg->addrSpaceSel; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); reg = MT9V111I_MODE_CONTROL; data = mt9v111_device.ifpReg->modeControl; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); return 0; } +#if 0 /*! * mt9v111 sensor get AE measurement window mode configuration * @@ -435,6 +707,7 @@ static void mt9v111_get_ae_mode(int *ae_mode) *ae_mode = (mt9v111_device.ifpReg->modeControl & 0xc) >> 2; } } +#endif #ifdef MT9V111_DEBUG /*! @@ -442,33 +715,33 @@ static void mt9v111_get_ae_mode(int *ae_mode) * * @return none */ -static void mt9v111_test_pattern(bool flag) +static void mt9v111_test_pattern(int sensorid , bool flag) { u16 data; /* switch to sensor registers */ - mt9v111_write_reg(MT9V111I_ADDR_SPACE_SEL, MT9V111I_SEL_SCA); + mt9v111_write_reg(sensorid,MT9V111I_ADDR_SPACE_SEL, MT9V111I_SEL_SCA); if (flag == true) { testpattern = MT9V111S_OUTCTRL_TEST_MODE; - data = mt9v111_read_reg(MT9V111S_ROW_NOISE_CTRL) & 0xBF; - mt9v111_write_reg(MT9V111S_ROW_NOISE_CTRL, data); + data = mt9v111_read_reg(sensorid,MT9V111S_ROW_NOISE_CTRL) & 0xBF; + mt9v111_write_reg(sensorid,MT9V111S_ROW_NOISE_CTRL, data); - mt9v111_write_reg(MT9V111S_TEST_DATA, 0); + mt9v111_write_reg(sensorid,MT9V111S_TEST_DATA, 0); /* changes take effect */ data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000; - mt9v111_write_reg(MT9V111S_OUTPUT_CTRL, data); + mt9v111_write_reg(sensorid,MT9V111S_OUTPUT_CTRL, data); } else { testpattern = 0; - data = mt9v111_read_reg(MT9V111S_ROW_NOISE_CTRL) | 0x40; + data = mt9v111_read_reg(sensorid,MT9V111S_ROW_NOISE_CTRL) | 0x40; mt9v111_write_reg(MT9V111S_ROW_NOISE_CTRL, data); /* changes take effect */ data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000; - mt9v111_write_reg(MT9V111S_OUTPUT_CTRL, data); + mt9v111_write_reg(sensorid,MT9V111S_OUTPUT_CTRL, data); } } #endif @@ -507,6 +780,7 @@ static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) p->u.bt656.clock_curr = MT9V111_MCLK; p->if_type = V4L2_IF_TYPE_BT656; p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.bt_sync_correct = 1; // translates to CSI ext vsync p->u.bt656.clock_min = MT9V111_CLK_MIN; p->u.bt656.clock_max = MT9V111_CLK_MAX; @@ -534,10 +808,12 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) sensor->on = on; - if (on) - gpio_sensor_active(); - else - gpio_sensor_inactive(); + if(on) { + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */, true, true); + } + else { + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */, false, false); + } return 0; } @@ -554,19 +830,23 @@ static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) int ret = 0; struct v4l2_captureparm *cparm = &a->parm.capture; /* s->priv points to mt9v111_data */ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); pr_debug("In mt9v111:ioctl_g_parm\n"); + if( sensorid < 0 ) + return ret; + switch (a->type) { /* This is the only case currently handled. */ case V4L2_BUF_TYPE_VIDEO_CAPTURE: pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); memset(a, 0, sizeof(*a)); a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cparm->capability = mt9v111_data.streamcap.capability; + cparm->capability = mt9v111_data[sensorid].streamcap.capability; cparm->timeperframe = - mt9v111_data.streamcap.timeperframe; - cparm->capturemode = mt9v111_data.streamcap.capturemode; + mt9v111_data[sensorid].streamcap.timeperframe; + cparm->capturemode = mt9v111_data[sensorid].streamcap.capturemode; ret = 0; break; @@ -605,9 +885,13 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) int ret = 0; struct v4l2_captureparm *cparm = &a->parm.capture; /* s->priv points to mt9v111_data */ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); pr_debug("In mt9v111:ioctl_s_parm\n"); + if( sensorid < 0 ) + return ret; + switch (a->type) { /* This is the only case currently handled. */ case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -617,13 +901,13 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) * Changing the frame rate is not allowed on this *camera. */ if (cparm->timeperframe.denominator != - mt9v111_data.streamcap.timeperframe.denominator) { + mt9v111_data[sensorid].streamcap.timeperframe.denominator) { pr_err("ERROR: mt9v111: ioctl_s_parm: " \ "This camera does not allow frame rate " "changes.\n"); ret = -EINVAL; } else { - mt9v111_data.streamcap.timeperframe = + mt9v111_data[sensorid].streamcap.timeperframe = cparm->timeperframe; /* Call any camera functions to match settings. */ } @@ -635,7 +919,7 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) "unsupported capture mode\n"); ret = -EINVAL; } else { - mt9v111_data.streamcap.capturemode = + mt9v111_data[sensorid].streamcap.capturemode = cparm->capturemode; /* Call any camera functions to match settings. */ /* Right now this camera only supports 1 mode. */ @@ -685,6 +969,7 @@ static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) return 0; } +#if 0 /*! * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl * @s: pointer to standard V4L2 device structure @@ -700,6 +985,7 @@ static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc) return 0; } +#endif /*! * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl @@ -712,66 +998,29 @@ static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc) */ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) { + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + pr_debug("In mt9v111:ioctl_g_ctrl\n"); + if( sensorid < 0 ) + return 0; + switch (vc->id) { case V4L2_CID_BRIGHTNESS: pr_debug(" V4L2_CID_BRIGHTNESS\n"); - vc->value = mt9v111_data.brightness; - break; - case V4L2_CID_CONTRAST: - pr_debug(" V4L2_CID_CONTRAST\n"); - vc->value = mt9v111_data.contrast; + vc->value = mt9v111_data[sensorid].brightness; break; case V4L2_CID_SATURATION: pr_debug(" V4L2_CID_SATURATION\n"); - vc->value = mt9v111_data.saturation; - break; - case V4L2_CID_HUE: - pr_debug(" V4L2_CID_HUE\n"); - vc->value = mt9v111_data.hue; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_AUTO_WHITE_BALANCE\n"); - vc->value = 0; - break; - case V4L2_CID_DO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_DO_WHITE_BALANCE\n"); - vc->value = 0; - break; - case V4L2_CID_RED_BALANCE: - pr_debug(" V4L2_CID_RED_BALANCE\n"); - vc->value = mt9v111_data.red; - break; - case V4L2_CID_BLUE_BALANCE: - pr_debug(" V4L2_CID_BLUE_BALANCE\n"); - vc->value = mt9v111_data.blue; - break; - case V4L2_CID_GAMMA: - pr_debug(" V4L2_CID_GAMMA\n"); - vc->value = 0; + vc->value = mt9v111_data[sensorid].saturation; break; case V4L2_CID_EXPOSURE: pr_debug(" V4L2_CID_EXPOSURE\n"); - vc->value = mt9v111_data.ae_mode; - break; - case V4L2_CID_AUTOGAIN: - pr_debug(" V4L2_CID_AUTOGAIN\n"); - vc->value = 0; + vc->value = mt9v111_data[sensorid].ae_mode; break; case V4L2_CID_GAIN: pr_debug(" V4L2_CID_GAIN\n"); - vc->value = 0; - break; - case V4L2_CID_HFLIP: - pr_debug(" V4L2_CID_HFLIP\n"); - vc->value = 0; - break; - case V4L2_CID_VFLIP: - pr_debug(" V4L2_CID_VFLIP\n"); - vc->value = 0; + vc->value = mt9v111_data[sensorid].gain; break; default: pr_debug(" Default case\n"); @@ -794,56 +1043,34 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) { int retval = 0; + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); pr_debug("In mt9v111:ioctl_s_ctrl %d\n", vc->id); + if( sensorid < 0 ) + return retval; + switch (vc->id) { case V4L2_CID_BRIGHTNESS: pr_debug(" V4L2_CID_BRIGHTNESS\n"); - break; - case V4L2_CID_CONTRAST: - pr_debug(" V4L2_CID_CONTRAST\n"); + mt9v111_set_digitalbrightness(sensorid,vc->value); + mt9v111_data[sensorid].brightness = vc->value; break; case V4L2_CID_SATURATION: pr_debug(" V4L2_CID_SATURATION\n"); - retval = mt9v111_set_saturation(vc->value); - break; - case V4L2_CID_HUE: - pr_debug(" V4L2_CID_HUE\n"); - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_AUTO_WHITE_BALANCE\n"); - break; - case V4L2_CID_DO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_DO_WHITE_BALANCE\n"); - break; - case V4L2_CID_RED_BALANCE: - pr_debug(" V4L2_CID_RED_BALANCE\n"); - break; - case V4L2_CID_BLUE_BALANCE: - pr_debug(" V4L2_CID_BLUE_BALANCE\n"); - break; - case V4L2_CID_GAMMA: - pr_debug(" V4L2_CID_GAMMA\n"); + retval = mt9v111_set_saturation(sensorid,vc->value); + mt9v111_data[sensorid].saturation = vc->value; break; case V4L2_CID_EXPOSURE: pr_debug(" V4L2_CID_EXPOSURE\n"); - retval = mt9v111_set_ae_mode(vc->value); - break; - case V4L2_CID_AUTOGAIN: - pr_debug(" V4L2_CID_AUTOGAIN\n"); + retval = mt9v111_set_ae_mode(sensorid,vc->value); + mt9v111_data[sensorid].ae_mode = vc->value; break; case V4L2_CID_GAIN: pr_debug(" V4L2_CID_GAIN\n"); - break; - case V4L2_CID_HFLIP: - pr_debug(" V4L2_CID_HFLIP\n"); - break; - case V4L2_CID_VFLIP: - pr_debug(" V4L2_CID_VFLIP\n"); + mt9v111_set_digitalsharpness(sensorid,vc->value); + mt9v111_data[sensorid].gain = vc->value; break; default: pr_debug(" Default case\n"); @@ -854,13 +1081,41 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) return retval; } +static void mt9v111_ifp_reset ( int sensorid ) +{ + mt9v111_write_reg(sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0001); + mt9v111_write_reg(sensorid,MT9V111I_SOFT_RESET, 0x0001); + msleep(100); + mt9v111_write_reg(sensorid,MT9V111I_SOFT_RESET, 0x0000); + msleep(100); +} + +static void mt9v111_sensor_reset ( int sensorid ) +{ + mt9v111_write_reg(sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0004); + mt9v111_write_reg(sensorid,MT9V111S_RESET, 0x0001); + msleep(100); + mt9v111_write_reg(sensorid,MT9V111S_RESET, 0x0000); + msleep(100); +} + /*! * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT * @s: pointer to standard V4L2 device structure */ static int ioctl_init(struct v4l2_int_device *s) { - pr_debug("In mt9v111:ioctl_init\n"); + int sensorid = 0; + + sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + if( sensorid < 0 ) + return 0; + + pr_debug("In mt9v111:ioctl_init for sensor %d\n",sensorid); + + mt9v111_sensor_reset(sensorid); + mt9v111_ifp_reset(sensorid); + mt9v111_sensor_lib_datasheet(sensorid,mt9v111_device.coreReg, mt9v111_device.ifpReg); return 0; } @@ -873,19 +1128,146 @@ static int ioctl_init(struct v4l2_int_device *s) */ static int ioctl_dev_init(struct v4l2_int_device *s) { + int sensorid = 0; uint32_t clock_rate = MT9V111_MCLK; + sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + if( sensorid < 0 ) + return 0; + pr_debug("In mt9v111:ioctl_dev_init\n"); - gpio_sensor_active(); + set_mclk_rate(&clock_rate, 0); // Both sensors use mclk0 on Digi ccwmx51 + + mt9v111_sensor_reset(sensorid); + mt9v111_ifp_reset(sensorid); + mt9v111_sensor_lib_datasheet(sensorid,mt9v111_device.coreReg, mt9v111_device.ifpReg); - set_mclk_rate(&clock_rate); - mt9v111_rate_cal(&reset_frame_rate, clock_rate); - mt9v111_sensor_lib(mt9v111_device.coreReg, mt9v111_device.ifpReg); + return 0; +} + +/* list of image formats supported by sensor */ +static const struct v4l2_fmtdesc mt9v111_formats[] = { + { + .description = "RGB565", + .pixelformat = V4L2_PIX_FMT_RGB565, + }, + { + .description = "YUV422 UYVY", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, +}; + +#define MT9V111_NUM_CAPTURE_FORMATS ARRAY_SIZE(mt9v111_formats) + +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + int index = fmt->index; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= MT9V111_NUM_CAPTURE_FORMATS) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + fmt->flags = mt9v111_formats[index].flags; + strlcpy(fmt->description, mt9v111_formats[index].description, + sizeof(fmt->description)); + fmt->pixelformat = mt9v111_formats[index].pixelformat; return 0; } +static int ioctl_s_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + unsigned short reg; + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + struct sensor *sensor = s->priv; + /* s->priv points to mt9v111_data */ + + if( sensorid < 0 ) + return -ENODEV; + + /* Select IFP registers */ + mt9v111_write_reg (sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0001); + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB565: + /*MT9V111I_OUTPUT_FORMAT_CTRL2*/ + reg = mt9v111_read_reg (sensorid,MT9V111I_OUTPUT_FORMAT_CTRL2); + reg &= ~(0x3 << 6); + mt9v111_write_reg (sensorid,MT9V111I_OUTPUT_FORMAT_CTRL2, reg); + + /* MT9V111I_FORMAT_CONTROL */ + reg = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL); + reg |= 1 << 12; + mt9v111_write_reg(sensorid,MT9V111I_FORMAT_CONTROL, reg); + break; + + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUYV: + /* MT9V111I_FORMAT_CONTROL */ + reg = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL); + reg &= ~(1 << 12); + mt9v111_write_reg(sensorid,MT9V111I_FORMAT_CONTROL, reg); + break; + + default: + return -EINVAL; + } + + sensor->pix.width = f->fmt.pix.width; + sensor->pix.height = f->fmt.pix.height; + sensor->pix.sizeimage = f->fmt.pix.sizeimage; + sensor->pix.pixelformat = f->fmt.pix.pixelformat; + return 0; +} + +static int ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + int i; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + for( i=0 ; i < MT9V111_NUM_CAPTURE_FORMATS ; i++) { + if( f->fmt.pix.pixelformat == mt9v111_formats[i].pixelformat ) + return 0; + } + + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ioctl_get_register(struct v4l2_int_device *s,struct v4l2_dbg_register * dreg) +{ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , true, true); + dreg->val = mt9v111_read_reg (sensorid,dreg->reg); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , false, false); + return 0; +} + +static int ioctl_set_register(struct v4l2_int_device *s,struct v4l2_dbg_register * dreg) +{ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , true, true); + mt9v111_write_reg (sensorid,dreg->reg, dreg->val); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , false, false); + return 0; +} +#endif + /*! * This structure defines all the ioctls for this module and links them to the * enumeration. @@ -910,16 +1292,23 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = { /*! * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type. */ -/* {vidioc_int_enum_fmt_cap_num, - (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, */ + {vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, + +#ifdef CONFIG_VIDEO_ADV_DEBUG + {vidioc_int_g_register_num, + (v4l2_int_ioctl_func *) ioctl_get_register}, + {vidioc_int_s_register_num, + (v4l2_int_ioctl_func *) ioctl_set_register}, +#endif /*! * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. * This ioctl is used to negotiate the image capture size and * pixel format without actually making it take effect. */ -/* {vidioc_int_try_fmt_cap_num, - (v4l2_int_ioctl_func *) ioctl_try_fmt_cap}, */ + {vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *) ioctl_try_fmt_cap}, {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap}, @@ -928,7 +1317,7 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = { * format, returns error code if format not supported or HW can't be * correctly configured. */ -/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */ + {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm}, {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm}, @@ -937,20 +1326,56 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = { {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl}, }; -static struct v4l2_int_slave mt9v111_slave = { - .ioctls = mt9v111_ioctl_desc, - .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc), +static struct v4l2_int_slave mt9v111_slave[] = { + { + .ioctls = mt9v111_ioctl_desc, + .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc), + .attach_to = "mxc_v4l2_cap_1", + }, + { + .ioctls = mt9v111_ioctl_desc, + .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc), + .attach_to = "mxc_v4l2_cap_2", + }, }; -static struct v4l2_int_device mt9v111_int_device = { - .module = THIS_MODULE, - .name = "mt9v111", - .type = v4l2_int_type_slave, - .u = { - .slave = &mt9v111_slave, +static struct v4l2_int_device mt9v111_int_device [] = { + { + .module = THIS_MODULE, + .type = v4l2_int_type_slave, + .u = { + .slave = &mt9v111_slave[0], + }, + }, + { + .module = THIS_MODULE, + .type = v4l2_int_type_slave, + .u = { + .slave = &mt9v111_slave[1], + }, }, }; +static int mt9v111_read_id( int sensoridx ) +{ + int sensorid = 0; + int ret = 0; + + mt9v111_write_reg (sensoridx,MT9V111S_ADDR_SPACE_SEL, 0x0004); + + sensorid = mt9v111_read_reg (sensoridx,MT9V111S_CHIP_VERSION); + if( sensorid == 0x823a ) + { + printk(KERN_INFO" MT9V111 ID %x\n",sensorid); + } + else + { + printk(KERN_ERR" MT9V111 Could not detect sensor (read %x)\n",sensorid); + ret = -ENODEV; + } + return ret; +} + /*! * mt9v111 I2C probe function * Function set in i2c_driver struct. @@ -962,32 +1387,56 @@ static int mt9v111_probe(struct i2c_client *client, const struct i2c_device_id *id) { int retval; + int sensorid; pr_debug("In mt9v111_probe device id is %s\n", id->name); + sensorid = mt9v111_id_from_name(id->name); + + if( sensorid < 0 ) + return -ENODEV; + /* Set initial values for the sensor struct. */ - memset(&mt9v111_data, 0, sizeof(mt9v111_data)); - mt9v111_data.i2c_client = client; + memset(&mt9v111_data[sensorid], 0, sizeof(struct sensor)); + mt9v111_data[sensorid].i2c_client = client; pr_debug(" client name is %s\n", client->name); - mt9v111_data.pix.pixelformat = V4L2_PIX_FMT_UYVY; - mt9v111_data.pix.width = MT9V111_MAX_WIDTH; - mt9v111_data.pix.height = MT9V111_MAX_HEIGHT; - mt9v111_data.streamcap.capability = 0; /* No higher resolution or frame - * frame rate changes supported. - */ - mt9v111_data.streamcap.timeperframe.denominator = MT9V111_FRAME_RATE; - mt9v111_data.streamcap.timeperframe.numerator = 1; + mt9v111_data[sensorid].pix.pixelformat = V4L2_PIX_FMT_UYVY; + mt9v111_data[sensorid].pix.width = MT9V111_MAX_WIDTH; + mt9v111_data[sensorid].pix.height = MT9V111_MAX_HEIGHT; + mt9v111_data[sensorid].streamcap.capability = 0; /* No higher resolution or frame + * frame rate changes supported.*/ + mt9v111_data[sensorid].streamcap.timeperframe.denominator = MT9V111_FRAME_RATE; + mt9v111_data[sensorid].streamcap.timeperframe.numerator = 1; + + strcpy(mt9v111_int_device[sensorid].name,id->name); + pr_debug(" video device name is %s\n", mt9v111_data[sensorid].v4l2_int_device->name); + mt9v111_data[sensorid].v4l2_int_device = &mt9v111_int_device[sensorid]; + mt9v111_int_device[sensorid].priv = &mt9v111_data[sensorid]; + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , true, true); + + if( mt9v111_read_id(sensorid) != 0) { + printk(KERN_ERR"mt9v111_probe: No sensor found\n"); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , false, false); + return -ENXIO; + } - mt9v111_int_device.priv = &mt9v111_data; +#ifdef MT9V111_DEBUG + mt9v111_test_pattern(1); +#endif + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , false, false); pr_debug(" type is %d (expect %d)\n", - mt9v111_int_device.type, v4l2_int_type_slave); + mt9v111_int_device[sensorid].type, v4l2_int_type_slave); pr_debug(" num ioctls is %d\n", - mt9v111_int_device.u.slave->num_ioctls); + mt9v111_int_device[sensorid].u.slave->num_ioctls); /* This function attaches this structure to the /dev/video0 device. * The pointer in priv points to the mt9v111_data structure here.*/ - retval = v4l2_int_device_register(&mt9v111_int_device); + retval = v4l2_int_device_register(&mt9v111_int_device[sensorid]); + if( retval == 0 ) + mt9v111_data[sensorid].used = 1; return retval; } @@ -998,9 +1447,14 @@ static int mt9v111_probe(struct i2c_client *client, */ static int mt9v111_remove(struct i2c_client *client) { + int i; + pr_debug("In mt9v111_remove\n"); - v4l2_int_device_unregister(&mt9v111_int_device); + for ( i=0 ; i < ARRAY_SIZE(mt9v111_int_device) ; i++ ) { + if( mt9v111_data[i].used ) + v4l2_int_device_unregister(&mt9v111_int_device[i]); + } return 0; } @@ -1033,13 +1487,13 @@ static __init int mt9v111_init(void) memset(mt9v111_device.ifpReg, 0, sizeof(mt9v111_IFPReg)); /* Set contents of the just created structures. */ - mt9v111_config(); + mt9v111_config_datasheet(); /* Tells the i2c driver what functions to call for this driver. */ err = i2c_add_driver(&mt9v111_i2c_driver); if (err != 0) pr_err("%s:driver registration failed, error=%d \n", - __func__, err); + __func__, err); return err; } @@ -1055,7 +1509,6 @@ static void __exit mt9v111_clean(void) pr_debug("In mt9v111_clean()\n"); i2c_del_driver(&mt9v111_i2c_driver); - gpio_sensor_inactive(); if (mt9v111_device.coreReg) { kfree(mt9v111_device.coreReg); diff --git a/drivers/media/video/mxc/capture/mt9v111.h b/drivers/media/video/mxc/capture/mt9v111.h index cf38cec4757c..ba91a722a076 100644 --- a/drivers/media/video/mxc/capture/mt9v111.h +++ b/drivers/media/video/mxc/capture/mt9v111.h @@ -111,11 +111,14 @@ #define MT9V111I_GAMMA_KNEE_Y90 0x57 #define MT9V111I_GAMMA_VALUE_Y0 0x58 #define MT9V111I_SHUTTER_60 0x59 +#define MT9V111I_AUTO_EXPOSURE_17 0x5A #define MT9V111I_SEARCH_FLICK_60 0x5c +#define MT9V111I_RESERVED93 0x5d #define MT9V111I_RATIO_IMAGE_GAIN_BASE 0x5e #define MT9V111I_RATIO_IMAGE_GAIN_DELTA 0x5f #define MT9V111I_SIGN_VALUE_REG5F 0x60 #define MT9V111I_AE_GAIN 0x62 +#define MT9V111I_RESERVED100 0x64 #define MT9V111I_MAX_GAIN_AE 0x67 #define MT9V111I_LENS_CORRECT_CTRL 0x80 #define MT9V111I_SHADING_PARAMETER1 0x81 @@ -173,6 +176,7 @@ #define MT9V111S_ROW_START_IN_ZOOM 0x13 #define MT9V111S_DIGITAL_ZOOM 0x1e #define MT9V111S_READ_MODE 0x20 +#define MT9V111S_RESERVED33 0x21 #define MT9V111S_DAC_CTRL 0x27 #define MT9V111S_GREEN1_GAIN 0x2b #define MT9V111S_BLUE_GAIN 0x2c @@ -278,6 +282,7 @@ typedef struct { u32 rowNoiseControl; u32 darkTargetwNC; u32 testData; /*!< test mode */ + u32 reserved33; u32 globalGain; u32 chipVersion; u32 darkTargetwoNC; @@ -375,11 +380,14 @@ typedef struct { u32 gammaKneeY90; /*!< Gamma knee points Y9 and Y10 */ u32 gammaKneeY0; /*!< Gamma knee point Y0 */ u32 shutter_width_60; + u32 auto_exposure_17; u32 search_flicker_60; + u32 reserved93; u32 ratioImageGainBase; u32 ratioImageGainDelta; u32 signValueReg5F; u32 aeGain; + u32 reserved100; u32 maxGainAE; u32 lensCorrectCtrl; u32 shadingParameter1; /*!< Shade Parameters */ diff --git a/drivers/media/video/mxc/capture/mx27_prpsw.c b/drivers/media/video/mxc/capture/mx27_prpsw.c index ce7db16913ec..eca200a580f2 100644 --- a/drivers/media/video/mxc/capture/mx27_prpsw.c +++ b/drivers/media/video/mxc/capture/mx27_prpsw.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -702,7 +702,7 @@ static int prp_still_start(void *private) cam_data *cam = (cam_data *) private; g_still_on = 1; - g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf; + g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf[0]; g_prp_cfg.ch2_ptr2 = 0; if (prp_v4l2_cfg(&g_prp_cfg, cam)) diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c index 30ad533b0ebd..be9a988aff2f 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c @@ -18,6 +18,8 @@ * * @ingroup MXC_V4L2_CAPTURE */ + + #include <linux/version.h> #include <linux/module.h> #include <linux/init.h> @@ -37,9 +39,9 @@ #include <media/v4l2-int-device.h> #include "mxc_v4l2_capture.h" #include "ipu_prp_sw.h" +#include "asm/delay.h" static int video_nr = -1; -static cam_data *g_cam; /*! This data is used for the output to the display. */ #define MXC_V4L2_CAPTURE_NUM_OUTPUTS 3 @@ -74,21 +76,23 @@ static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = { static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = { { .index = 0, - .name = "CSI IC MEM", + .name = "CSI MEM", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 0, .tuner = 0, .std = V4L2_STD_UNKNOWN, - .status = 0, + .status = V4L2_IN_ST_NO_POWER, }, { .index = 1, +// AG: CSI IC MEM works but has problems +// .name = "CSI IC MEM", .name = "CSI MEM", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 0, .tuner = 0, .std = V4L2_STD_UNKNOWN, - .status = V4L2_IN_ST_NO_POWER, + .status = 0, }, }; @@ -118,6 +122,7 @@ typedef struct { u16 active_left; /*!< Active left. */ } video_fmt_t; +#if 0 /*! * Description of video formats supported. * @@ -128,37 +133,39 @@ static video_fmt_t video_fmts[] = { { /*! NTSC */ .v4l2_id = V4L2_STD_NTSC, .name = "NTSC", - .raw_width = 720 - 1, /* SENS_FRM_WIDTH */ - .raw_height = 288 - 1, /* SENS_FRM_HEIGHT */ - .active_width = 720, /* ACT_FRM_WIDTH plus 1 */ - .active_height = (480 / 2), /* ACT_FRM_HEIGHT plus 1 */ - .active_top = 12, + .raw_width = 720, /* SENS_FRM_WIDTH */ + .raw_height = 525, /* SENS_FRM_HEIGHT */ + .active_width = 720, /* ACT_FRM_WIDTH */ + .active_height = 240, /* ACT_FRM_HEIGHT */ + .active_top = 0, .active_left = 0, }, { /*! (B, G, H, I, N) PAL */ .v4l2_id = V4L2_STD_PAL, .name = "PAL", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 288, .active_top = 0, .active_left = 0, }, { /*! Unlocked standard */ .v4l2_id = V4L2_STD_ALL, .name = "Autodetect", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 288, .active_top = 0, .active_left = 0, }, }; + /*!* Standard index of TV. */ static video_fmt_idx video_index = TV_NOT_LOCKED; +#endif static int mxc_v4l2_master_attach(struct v4l2_int_device *slave); static void mxc_v4l2_master_detach(struct v4l2_int_device *slave); @@ -172,15 +179,27 @@ static struct v4l2_int_master mxc_v4l2_master = { .detach = mxc_v4l2_master_detach, }; -static struct v4l2_int_device mxc_v4l2_int_device = { +static struct v4l2_int_device mxc_v4l2_int_device [] = { + { + .module = THIS_MODULE, + .name = "mxc_v4l2_cap_1", + .type = v4l2_int_type_master, + .u = { + .master = &mxc_v4l2_master, + }, + }, + { .module = THIS_MODULE, - .name = "mxc_v4l2_cap", + .name = "mxc_v4l2_cap_2", .type = v4l2_int_type_master, .u = { .master = &mxc_v4l2_master, }, + }, }; +static cam_data *g_cam[ARRAY_SIZE(mxc_v4l2_int_device)]; + /*************************************************************************** * Functions for handling Frame buffers. **************************************************************************/ @@ -260,6 +279,7 @@ static int mxc_allocate_frame_buf(cam_data *cam, int count) static void mxc_free_frames(cam_data *cam) { int i; + unsigned long lock_flags; pr_debug("In MVC:mxc_free_frames\n"); @@ -269,9 +289,11 @@ static void mxc_free_frames(cam_data *cam) cam->enc_counter = 0; cam->skip_frame = 0; + spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags); INIT_LIST_HEAD(&cam->ready_q); INIT_LIST_HEAD(&cam->working_q); INIT_LIST_HEAD(&cam->done_q); + spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); } /*! @@ -331,8 +353,7 @@ static int mxc_streamon(cam_data *cam) { struct mxc_v4l_frame *frame; int err = 0; - - pr_debug("In MVC:mxc_streamon\n"); + unsigned long lock_flags; if (NULL == cam) { pr_err("ERROR! cam parameter is NULL\n"); @@ -363,23 +384,27 @@ static int mxc_streamon(cam_data *cam) } } + spin_lock_irqsave(&cam->queue_int_lock, lock_flags); cam->ping_pong_csi = 0; if (cam->enc_update_eba) { - frame = - list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); - list_del(cam->ready_q.next); - list_add_tail(&frame->queue, &cam->working_q); - err = cam->enc_update_eba(frame->buffer.m.offset, - &cam->ping_pong_csi); frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&frame->queue, &cam->working_q); - err |= cam->enc_update_eba(frame->buffer.m.offset, - &cam->ping_pong_csi); + err = cam->enc_update_eba(cam->csi,frame->buffer.m.offset, + &cam->ping_pong_csi); + if (!list_empty(&cam->ready_q)) { + frame = + list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); + list_del(cam->ready_q.next); + list_add_tail(&frame->queue, &cam->working_q); + err |= cam->enc_update_eba(cam->csi,frame->buffer.m.offset, + &cam->ping_pong_csi); + } + cam->capture_on = true; } else { - return -EINVAL; + err = -EINVAL; } if (cam->overlay_on == true) @@ -387,11 +412,9 @@ static int mxc_streamon(cam_data *cam) if (cam->enc_enable_csi) { err = cam->enc_enable_csi(cam); - if (err != 0) - return err; } - cam->capture_on = true; + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); return err; } @@ -543,8 +566,6 @@ static int start_preview(cam_data *cam) { int err = 0; - pr_debug("MVC: start_preview\n"); - #if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE) pr_debug(" This is an SDC display\n"); if (cam->output == 0 || cam->output == 2) { @@ -602,8 +623,6 @@ static int stop_preview(cam_data *cam) { int err = 0; - pr_debug("MVC: stop preview\n"); - #if defined(CONFIG_MXC_IPU_PRP_VF_ADC) || defined(CONFIG_MXC_IPU_PRP_VF_ADC_MODULE) if (cam->output == 1) { err = prp_vf_adc_deselect(cam); @@ -674,6 +693,29 @@ static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f) __func__, cam->crop_current.width, cam->crop_current.height); + retval = vidioc_int_g_fmt_cap(cam->sensor,f); + return retval; +} + +/*! + * V4L2 - mxc_v4l2_enum_fmt function + * + * @param cam structure cam_data * + * + * @param f structure v4l2_fmtdesc * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_enum_fmt(cam_data *cam, struct v4l2_fmtdesc *f) +{ + int retval = 0; + + pr_debug("In MVC: mxc_v4l2_enum_fmt\n"); + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); + retval = vidioc_int_enum_fmt_cap(cam->sensor,f); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); + return retval; } @@ -709,10 +751,14 @@ static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) * for CSI MEM input mode. */ if (strcmp(mxc_capture_inputs[cam->current_input].name, - "CSI MEM") == 0) { + "CSI MEM") == 0 || strcmp(mxc_capture_inputs[cam->current_input].name, + "CSI IC MEM") == 0) { f->fmt.pix.width = cam->crop_current.width; f->fmt.pix.height = cam->crop_current.height; } + else { + printk("Error no match %s\n",mxc_capture_inputs[cam->current_input].name); + } if (cam->rotation >= IPU_ROTATE_90_RIGHT) { height = &f->fmt.pix.width; @@ -811,6 +857,13 @@ static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) break; } } + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, + true, true); + vidioc_int_s_fmt_cap(cam->sensor, f); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, + false, false); + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); @@ -1057,63 +1110,10 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) return ret; } -/*! - * V4L2 - mxc_v4l2_s_param function - * Allows setting of capturemode and frame rate. - * - * @param cam structure cam_data * - * @param parm structure v4l2_streamparm * - * - * @return status 0 success, EINVAL failed - */ -static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) -{ - struct v4l2_ifparm ifparm; +static int mxc_v4l2_init_csi( cam_data *cam ) { struct v4l2_format cam_fmt; - struct v4l2_streamparm currentparm; ipu_csi_signal_cfg_t csi_param; - int err = 0; - - pr_debug("In mxc_v4l2_s_param\n"); - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n"); - return -EINVAL; - } - - /* Stop the viewfinder */ - if (cam->overlay_on == true) { - stop_preview(cam); - } - - currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - /* First check that this device can support the changes requested. */ - err = vidioc_int_g_parm(cam->sensor, ¤tparm); - if (err) { - pr_err("%s: vidioc_int_g_parm returned an error %d\n", - __func__, err); - goto exit; - } - - pr_debug(" Current capabilities are %x\n", - currentparm.parm.capture.capability); - pr_debug(" Current capturemode is %d change to %d\n", - currentparm.parm.capture.capturemode, - parm->parm.capture.capturemode); - pr_debug(" Current framerate is %d change to %d\n", - currentparm.parm.capture.timeperframe.denominator, - parm->parm.capture.timeperframe.denominator); - - /* This will change any camera settings needed. */ - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); - err = vidioc_int_s_parm(cam->sensor, parm); - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); - if (err) { - pr_err("%s: vidioc_int_s_parm returned an error %d\n", - __func__, err); - goto exit; - } + struct v4l2_ifparm ifparm; /* If resolution changed, need to re-program the CSI */ /* Get new values. */ @@ -1131,13 +1131,13 @@ static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) csi_param.force_eof = 0; csi_param.data_en_pol = 0; csi_param.data_fmt = 0; - csi_param.csi = 0; + csi_param.csi = cam->csi; csi_param.mclk = 0; /* This may not work on other platforms. Check when adding a new one.*/ pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr); if (ifparm.u.bt656.clock_curr == 0) { - csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; + csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; } else { csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; } @@ -1189,7 +1189,63 @@ static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) ipu_csi_init_interface(cam->crop_bounds.width, cam->crop_bounds.height, cam_fmt.fmt.pix.pixelformat, csi_param); + return 0; +} +/*! + * V4L2 - mxc_v4l2_s_param function + * Allows setting of capturemode and frame rate. + * + * @param cam structure cam_data * + * @param parm structure v4l2_streamparm * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) +{ + struct v4l2_streamparm currentparm; + int err = 0; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n"); + return -EINVAL; + } + + /* Stop the viewfinder */ + if (cam->overlay_on == true) { + stop_preview(cam); + } + + currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* First check that this device can support the changes requested. */ + err = vidioc_int_g_parm(cam->sensor, ¤tparm); + if (err) { + pr_err("%s: vidioc_int_g_parm returned an error %d\n", + __func__, err); + goto exit; + } + + pr_debug(" Current capabilities are %x\n", + currentparm.parm.capture.capability); + pr_debug(" Current capturemode is %d change to %d\n", + currentparm.parm.capture.capturemode, + parm->parm.capture.capturemode); + pr_debug(" Current framerate is %d change to %d\n", + currentparm.parm.capture.timeperframe.denominator, + parm->parm.capture.timeperframe.denominator); + + /* This will change any camera settings needed. */ + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); + err = vidioc_int_s_parm(cam->sensor, parm); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); + if (err) { + pr_err("%s: vidioc_int_s_parm returned an error %d\n", + __func__, err); + goto exit; + } + + err = mxc_v4l2_init_csi(cam); exit: if (cam->overlay_on == true) @@ -1198,6 +1254,7 @@ exit: return err; } +#if 0 /*! * V4L2 - mxc_v4l2_s_std function * @@ -1287,6 +1344,7 @@ static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e) return 0; } +#endif /*! * Dequeue one V4L capture buffer @@ -1372,6 +1430,11 @@ static int mxc_v4l_open(struct file *file) return -EBADF; } + if(!cam->sensor) { + pr_err("ERROR: v4l2 capture: Unattached sensor!\n"); + return -EBADF; + } + down(&cam->busy_lock); err = 0; if (signal_pending(current)) @@ -1411,12 +1474,9 @@ static int mxc_v4l_open(struct file *file) csi_param.force_eof = 0; csi_param.data_en_pol = 0; csi_param.mclk = ifparm.u.bt656.clock_curr; - + csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct; csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; - /* Once we handle multiple inputs this will need to change. */ - csi_param.csi = 0; - if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) csi_param.data_width = IPU_CSI_DATA_WIDTH_8; @@ -1464,11 +1524,13 @@ static int mxc_v4l_open(struct file *file) __func__, cam->crop_current.width, cam->crop_current.height); + udelay(100); + csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat; pr_debug("On Open: Input to ipu size is %d x %d\n", cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); ipu_csi_set_window_size(cam->crop_current.width, - cam->crop_current.width, + cam->crop_current.height, cam->csi); ipu_csi_set_window_pos(cam->crop_current.left, cam->crop_current.top, @@ -1478,12 +1540,16 @@ static int mxc_v4l_open(struct file *file) cam_fmt.fmt.pix.pixelformat, csi_param); + udelay(100); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); vidioc_int_init(cam->sensor); ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); + + udelay(100); } file->private_data = dev; @@ -1519,7 +1585,7 @@ static int mxc_v4l_close(struct file *file) err = stop_preview(cam); cam->overlay_on = false; } - if (cam->capture_pid == current->pid) { + if (cam->capture_pid == current->tgid) { err |= mxc_streamoff(cam); wake_up_interruptible(&cam->enc_queue); } @@ -1570,7 +1636,7 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int err = 0; - u8 *v_address; + u8 *v_address[2]; struct video_device *dev = video_devdata(file); cam_data *cam = video_get_drvdata(dev); @@ -1581,11 +1647,17 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, if (cam->overlay_on == true) stop_preview(cam); - v_address = dma_alloc_coherent(0, + v_address[0] = dma_alloc_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), - &cam->still_buf, GFP_DMA | GFP_KERNEL); + &cam->still_buf[0], + GFP_DMA | GFP_KERNEL); + + v_address[1] = dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->still_buf[1], + GFP_DMA | GFP_KERNEL); - if (!v_address) { + if (!v_address[0] || !v_address[1]) { err = -ENOBUFS; goto exit0; } @@ -1593,14 +1665,14 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, err = prp_still_select(cam); if (err != 0) { err = -EIO; - goto exit1; + goto exit0; } cam->still_counter = 0; err = cam->csi_start(cam); if (err != 0) { err = -EIO; - goto exit2; + goto exit1; } if (!wait_event_interruptible_timeout(cam->still_queue, @@ -1609,19 +1681,23 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n", cam->still_counter); err = -ETIME; - goto exit2; + goto exit1; } - err = copy_to_user(buf, v_address, cam->v2f.fmt.pix.sizeimage); - - exit2: - prp_still_deselect(cam); + err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage); exit1: - dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address, - cam->still_buf); - cam->still_buf = 0; + prp_still_deselect(cam); exit0: + if (v_address[0] != 0) + dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[0], + cam->still_buf[0]); + if (v_address[1] != 0) + dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[1], + cam->still_buf[1]); + + cam->still_buf[0] = cam->still_buf[1] = 0; + if (cam->overlay_on == true) { start_preview(cam); } @@ -1661,6 +1737,21 @@ static long mxc_v4l_do_ioctl(struct file *file, return -EBUSY; switch (ioctlnr) { + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_S_REGISTER: { + struct v4l2_dbg_register * dreg = arg; + vidioc_int_s_register(cam->sensor,dreg); + break; + } + + case VIDIOC_DBG_G_REGISTER: { + struct v4l2_dbg_register * dreg = arg; + vidioc_int_g_register(cam->sensor,dreg); + break; + } +#endif + /*! * V4l2 VIDIOC_QUERYCAP ioctl */ @@ -1695,6 +1786,14 @@ static long mxc_v4l_do_ioctl(struct file *file, struct v4l2_format *sf = arg; pr_debug(" case VIDIOC_S_FMT\n"); retval = mxc_v4l2_s_fmt(cam, sf); + mxc_v4l2_init_csi(cam); + break; + } + + case VIDIOC_ENUM_FMT: { + struct v4l2_fmtdesc *fd = arg; + pr_debug(" case VIDIOC_ENUM_FMT\n"); + retval = mxc_v4l2_enum_fmt(cam, fd); break; } @@ -1775,9 +1874,8 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->skip_frame > 0) { list_add_tail(&cam->frame[index].queue, &cam->working_q); - retval = - cam->enc_update_eba(cam-> + cam->enc_update_eba(cam->csi,cam-> frame[index]. buffer.m.offset, &cam-> @@ -1999,28 +2097,6 @@ static long mxc_v4l_do_ioctl(struct file *file, break; } - /* linux v4l2 bug, kernel c0485619 user c0405619 */ - case VIDIOC_ENUMSTD: { - struct v4l2_standard *e = arg; - pr_debug(" case VIDIOC_ENUMSTD\n"); - *e = cam->standard; - break; - } - - case VIDIOC_G_STD: { - v4l2_std_id *e = arg; - pr_debug(" case VIDIOC_G_STD\n"); - retval = mxc_v4l2_g_std(cam, e); - break; - } - - case VIDIOC_S_STD: { - v4l2_std_id *e = arg; - pr_debug(" case VIDIOC_S_STD\n"); - retval = mxc_v4l2_s_std(cam, *e); - - break; - } case VIDIOC_ENUMOUTPUT: { struct v4l2_output *output = arg; @@ -2109,8 +2185,13 @@ static long mxc_v4l_do_ioctl(struct file *file, break; } - case VIDIOC_ENUM_FMT: - case VIDIOC_TRY_FMT: + case VIDIOC_TRY_FMT: { + struct v4l2_format * f = arg; + pr_debug(" case VIDIOC_TRY_FMT\n"); + retval = vidioc_int_try_fmt_cap(cam->sensor,f); + break; + } + case VIDIOC_QUERYCTRL: case VIDIOC_G_TUNER: case VIDIOC_S_TUNER: @@ -2163,7 +2244,7 @@ static int mxc_mmap(struct file *file, struct vm_area_struct *vma) return -EINTR; size = vma->vm_end - vma->vm_start; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, vma->vm_page_prot)) { @@ -2236,12 +2317,21 @@ static void camera_platform_release(struct device *device) } /*! Device Definition for Mt9v111 devices */ -static struct platform_device mxc_v4l2_devices = { - .name = "mxc_v4l2", - .dev = { - .release = camera_platform_release, - }, - .id = 0, +static struct platform_device mxc_v4l2_devices[] = { + { + .name = "mxc_v4l2_1", + .dev = { + .release = camera_platform_release, + }, + .id = 0, + }, + { + .name = "mxc_v4l2_2", + .dev = { + .release = camera_platform_release, + }, + .id = 1, + } }; /*! @@ -2302,7 +2392,7 @@ static void camera_callback(u32 mask, void *dev) struct mxc_v4l_frame, queue); - if (cam->enc_update_eba( + if (cam->enc_update_eba(cam->csi, ready_frame->buffer.m.offset, &cam->ping_pong_csi) == 0) { list_del(cam->ready_q.next); @@ -2354,7 +2444,7 @@ static void camera_callback(u32 mask, void *dev) ready_frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); - if (cam->enc_update_eba(ready_frame->buffer.m.offset, + if (cam->enc_update_eba(cam->csi,ready_frame->buffer.m.offset, &cam->ping_pong_csi) == 0) { list_del(cam->ready_q.next); list_add_tail(&ready_frame->queue, @@ -2362,7 +2452,7 @@ static void camera_callback(u32 mask, void *dev) } else return; } else { - if (cam->enc_update_eba( + if (cam->enc_update_eba(cam->csi, cam->dummy_frame.buffer.m.offset, &cam->ping_pong_csi) == -EACCES) return; @@ -2379,13 +2469,15 @@ static void camera_callback(u32 mask, void *dev) * * @return status 0 Success */ -static void init_camera_struct(cam_data *cam) +static void init_camera_struct(cam_data *cam,unsigned int csi) { - pr_debug("In MVC: init_camera_struct\n"); + pr_debug("In MVC: init_camera_struct for csi %d\n",csi); /* Default everything to 0 */ memset(cam, 0, sizeof(cam_data)); + cam->csi = csi; + init_MUTEX(&cam->param_lock); init_MUTEX(&cam->busy_lock); @@ -2396,7 +2488,7 @@ static void init_camera_struct(cam_data *cam) *(cam->video_dev) = mxc_v4l_template; video_set_drvdata(cam->video_dev, cam); - dev_set_drvdata(&mxc_v4l2_devices.dev, (void *)cam); + dev_set_drvdata(&mxc_v4l2_devices[csi].dev, (void *)cam); cam->video_dev->minor = -1; init_waitqueue_head(&cam->enc_queue); @@ -2428,6 +2520,8 @@ static void init_camera_struct(cam_data *cam) cam->skip_frame = 0; cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY; + cam->current_input = cam->csi; + cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2; cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2; cam->v2f.fmt.pix.width = 288; @@ -2438,9 +2532,6 @@ static void init_camera_struct(cam_data *cam) cam->win.w.left = 0; cam->win.w.top = 0; - cam->csi = 0; /* Need to determine how to set this correctly with - * multiple video input devices. */ - cam->enc_callback = camera_callback; init_waitqueue_head(&cam->power_queue); spin_lock_init(&cam->queue_int_lock); @@ -2460,11 +2551,12 @@ static u8 camera_power(cam_data *cam, bool cameraOn) { pr_debug("In MVC:camera_power on=%d\n", cameraOn); + if( !cam->open_count ) + return 0; + if (cameraOn == true) { - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); vidioc_int_s_power(cam->sensor, 1); } else { - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); vidioc_int_s_power(cam->sensor, 0); } return 0; @@ -2491,15 +2583,15 @@ static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state) return -1; } + if (!cam->open_count) { + return 0; + } + cam->low_power = true; if (cam->overlay_on == true) stop_preview(cam); - if ((cam->capture_on == true) && cam->enc_disable) { - cam->enc_disable(cam); - } camera_power(cam, false); - return 0; } @@ -2522,14 +2614,19 @@ static int mxc_v4l2_resume(struct platform_device *pdev) return -1; } + if( !cam->open_count ) + return 0; + cam->low_power = false; wake_up_interruptible(&cam->power_queue); + camera_power(cam, true); if (cam->overlay_on == true) start_preview(cam); + if (cam->capture_on == true) - mxc_streamon(cam); + mxc_streamon(cam); return 0; } @@ -2537,15 +2634,27 @@ static int mxc_v4l2_resume(struct platform_device *pdev) /*! * This structure contains pointers to the power management callback functions. */ -static struct platform_driver mxc_v4l2_driver = { - .driver = { - .name = "mxc_v4l2", - }, - .probe = NULL, - .remove = NULL, - .suspend = mxc_v4l2_suspend, - .resume = mxc_v4l2_resume, - .shutdown = NULL, +static struct platform_driver mxc_v4l2_driver[] = { + { + .driver = { + .name = "mxc_v4l2_1", + }, + .probe = NULL, + .remove = NULL, + .suspend = mxc_v4l2_suspend, + .resume = mxc_v4l2_resume, + .shutdown = NULL, + }, + { + .driver = { + .name = "mxc_v4l2_2", + }, + .probe = NULL, + .remove = NULL, + .suspend = mxc_v4l2_suspend, + .resume = mxc_v4l2_resume, + .shutdown = NULL, + }, }; /*! @@ -2567,6 +2676,7 @@ static int mxc_v4l2_master_attach(struct v4l2_int_device *slave) } ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); + vidioc_int_s_power(cam->sensor, 1); vidioc_int_dev_init(slave); ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -2623,53 +2733,55 @@ static void mxc_v4l2_master_detach(struct v4l2_int_device *slave) static __init int camera_init(void) { u8 err = 0; + int i; pr_debug("In MVC:camera_init\n"); - /* Register the device driver structure. */ - err = platform_driver_register(&mxc_v4l2_driver); - if (err != 0) { - pr_err("ERROR: v4l2 capture:camera_init: " - "platform_driver_register failed.\n"); - return err; - } + for (i = 0; i < ARRAY_SIZE(mxc_v4l2_int_device); i++) { + /* Register the device driver structure. */ + err = platform_driver_register(&mxc_v4l2_driver[i]); + if (err != 0) { + pr_err("ERROR: v4l2 capture:camera_init: " + "platform_driver_register failed.\n"); + return err; + } - /* Create g_cam and initialize it. */ - if ((g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) { - pr_err("ERROR: v4l2 capture: failed to register camera\n"); - platform_driver_unregister(&mxc_v4l2_driver); - return -1; - } - init_camera_struct(g_cam); + /* Create g_cam and initialize it. */ + if ((g_cam [i] = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) { + pr_err("ERROR: v4l2 capture: failed to register camera\n"); + platform_driver_unregister(&mxc_v4l2_driver[i]); + return -1; + } + init_camera_struct(g_cam [i], i); - /* Set up the v4l2 device and register it*/ - mxc_v4l2_int_device.priv = g_cam; - /* This function contains a bug that won't let this be rmmod'd. */ - v4l2_int_device_register(&mxc_v4l2_int_device); + /* Set up the v4l2 device and register it*/ + mxc_v4l2_int_device[i].priv = g_cam [i]; + /* This function contains a bug that won't let this be rmmod'd. */ + v4l2_int_device_register(&mxc_v4l2_int_device[i]); - /* Register the I2C device */ - err = platform_device_register(&mxc_v4l2_devices); - if (err != 0) { - pr_err("ERROR: v4l2 capture: camera_init: " - "platform_device_register failed.\n"); - platform_driver_unregister(&mxc_v4l2_driver); - kfree(g_cam); - g_cam = NULL; - return err; - } + /* Register the I2C device */ + err = platform_device_register(&mxc_v4l2_devices[i]); + if (err != 0) { + pr_err("ERROR: v4l2 capture: camera_init: " + "platform_device_register failed.\n"); + platform_driver_unregister(&mxc_v4l2_driver[i]); + kfree(g_cam [i]); + g_cam [i] = NULL; + return err; + } - /* register v4l video device */ - if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr) - == -1) { - platform_device_unregister(&mxc_v4l2_devices); - platform_driver_unregister(&mxc_v4l2_driver); - kfree(g_cam); - g_cam = NULL; - pr_err("ERROR: v4l2 capture: video_register_device failed\n"); - return -1; + /* register v4l video device */ + if (video_register_device(g_cam[i]->video_dev, VFL_TYPE_GRABBER, video_nr)== -1) { + platform_device_unregister(&mxc_v4l2_devices[i]); + platform_driver_unregister(&mxc_v4l2_driver[i]); + kfree(g_cam[i]); + g_cam [i] = NULL; + pr_err("ERROR: v4l2 capture: video_register_device failed\n"); + return -1; + } + pr_debug(" Video device registered: %s #%d\n", + g_cam[i]->video_dev->name, g_cam[i]->video_dev->minor); } - pr_debug(" Video device registered: %s #%d\n", - g_cam->video_dev->name, g_cam->video_dev->minor); return err; } @@ -2683,19 +2795,34 @@ static void __exit camera_exit(void) pr_info("V4L2 unregistering video\n"); - if (g_cam->open_count) { + if (g_cam[0]->open_count) { + pr_err("ERROR: v4l2 capture:camera open " + "-- setting ops to NULL\n"); + } else { + pr_info("V4L2 freeing image input device\n"); + v4l2_int_device_unregister(&mxc_v4l2_int_device[0]); + video_unregister_device(g_cam[0]->video_dev); + platform_driver_unregister(&mxc_v4l2_driver[0]); + platform_device_unregister(&mxc_v4l2_devices[0]); + + mxc_free_frame_buf(g_cam[0]); + kfree(g_cam[0]); + g_cam[0] = NULL; + } + + if (g_cam[1]->open_count) { pr_err("ERROR: v4l2 capture:camera open " "-- setting ops to NULL\n"); } else { pr_info("V4L2 freeing image input device\n"); - v4l2_int_device_unregister(&mxc_v4l2_int_device); - video_unregister_device(g_cam->video_dev); - platform_driver_unregister(&mxc_v4l2_driver); - platform_device_unregister(&mxc_v4l2_devices); - - mxc_free_frame_buf(g_cam); - kfree(g_cam); - g_cam = NULL; + v4l2_int_device_unregister(&mxc_v4l2_int_device[1]); + video_unregister_device(g_cam[1]->video_dev); + platform_driver_unregister(&mxc_v4l2_driver[1]); + platform_device_unregister(&mxc_v4l2_devices[1]); + + mxc_free_frame_buf(g_cam[1]); + kfree(g_cam[1]); + g_cam[1] = NULL; } } diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h index 45a211a80a38..abaaaea48447 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h @@ -36,6 +36,7 @@ #include <media/v4l2-dev.h> #define FRAME_NUM 3 +//#define FRAME_NUM 4 /*! * v4l2 frame structure. @@ -123,7 +124,7 @@ typedef struct _cam_data { /* still image capture */ wait_queue_head_t still_queue; int still_counter; - dma_addr_t still_buf; + dma_addr_t still_buf[2]; void *still_buf_vaddr; /* overlay */ @@ -166,7 +167,7 @@ typedef struct _cam_data { struct v4l2_rect crop_defrect; struct v4l2_rect crop_current; - int (*enc_update_eba) (dma_addr_t eba, int *bufferNum); + int (*enc_update_eba) (int csi,dma_addr_t eba, int *bufferNum); int (*enc_enable) (void *private); int (*enc_disable) (void *private); int (*enc_enable_csi) (void *private); @@ -194,6 +195,7 @@ typedef struct _cam_data { /* camera sensor interface */ struct camera_sensor *cam_sensor; /* old version */ struct v4l2_int_device *sensor; + struct timeval tv_wakeup; // TODO - for testing. Remove later } cam_data; #if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \ diff --git a/drivers/media/video/mxc/capture/ov3640.c b/drivers/media/video/mxc/capture/ov3640.c index 29e61234e7f8..899945b7d071 100644 --- a/drivers/media/video/mxc/capture/ov3640.c +++ b/drivers/media/video/mxc/capture/ov3640.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -26,7 +26,7 @@ #define OV3640_VOLTAGE_ANALOG 2800000 #define OV3640_VOLTAGE_DIGITAL_CORE 1500000 #define OV3640_VOLTAGE_DIGITAL_IO 1800000 - +#define OV3640_VOLTAGE_DIGITAL_GPO 2800000 /* Check these values! */ #define MIN_FPS 15 @@ -40,8 +40,8 @@ enum ov3640_mode { ov3640_mode_MIN = 0, ov3640_mode_VGA_640_480 = 0, ov3640_mode_QVGA_320_240 = 1, - ov3640_mode_QXGA_2048_1536 = 2, - ov3640_mode_XGA_1024_768 = 3, + ov3640_mode_XGA_1024_768 = 2, + ov3640_mode_QXGA_2048_1536 = 3, ov3640_mode_NTSC_720_480 = 4, ov3640_mode_PAL_720_576 = 5, ov3640_mode_MAX = 5 @@ -93,6 +93,44 @@ struct sensor { } ov3640_data; static struct reg_value ov3640_setting_15fps_QXGA_2048_1536[] = { +#if 0 + /* The true 15fps QXGA setting. */ + {0x3012, 0x80, 0, 0}, {0x304d, 0x41, 0, 0}, {0x3087, 0x16, 0, 0}, + {0x30aa, 0x45, 0, 0}, {0x30b0, 0xff, 0, 0}, {0x30b1, 0xff, 0, 0}, + {0x30b2, 0x13, 0, 0}, {0x30d7, 0x10, 0, 0}, {0x309e, 0x00, 0, 0}, + {0x3602, 0x26, 0, 0}, {0x3603, 0x4D, 0, 0}, {0x364c, 0x04, 0, 0}, + {0x360c, 0x12, 0, 0}, {0x361e, 0x00, 0, 0}, {0x361f, 0x11, 0, 0}, + {0x3633, 0x03, 0, 0}, {0x3629, 0x3c, 0, 0}, {0x300e, 0x33, 0, 0}, + {0x300f, 0x21, 0, 0}, {0x3010, 0x20, 0, 0}, {0x3011, 0x00, 0, 0}, + {0x304c, 0x81, 0, 0}, {0x3029, 0x47, 0, 0}, {0x3070, 0x00, 0, 0}, + {0x3071, 0xEC, 0, 0}, {0x301C, 0x06, 0, 0}, {0x3072, 0x00, 0, 0}, + {0x3073, 0xC5, 0, 0}, {0x301D, 0x07, 0, 0}, {0x3018, 0x38, 0, 0}, + {0x3019, 0x30, 0, 0}, {0x301a, 0x61, 0, 0}, {0x307d, 0x00, 0, 0}, + {0x3087, 0x02, 0, 0}, {0x3082, 0x20, 0, 0}, {0x303c, 0x08, 0, 0}, + {0x303d, 0x18, 0, 0}, {0x303e, 0x06, 0, 0}, {0x303F, 0x0c, 0, 0}, + {0x3030, 0x62, 0, 0}, {0x3031, 0x26, 0, 0}, {0x3032, 0xe6, 0, 0}, + {0x3033, 0x6e, 0, 0}, {0x3034, 0xea, 0, 0}, {0x3035, 0xae, 0, 0}, + {0x3036, 0xa6, 0, 0}, {0x3037, 0x6a, 0, 0}, {0x3015, 0x12, 0, 0}, + {0x3014, 0x04, 0, 0}, {0x3013, 0xf7, 0, 0}, {0x3104, 0x02, 0, 0}, + {0x3105, 0xfd, 0, 0}, {0x3106, 0x00, 0, 0}, {0x3107, 0xff, 0, 0}, + {0x3308, 0xa5, 0, 0}, {0x3316, 0xff, 0, 0}, {0x3317, 0x00, 0, 0}, + {0x3087, 0x02, 0, 0}, {0x3082, 0x20, 0, 0}, {0x3300, 0x13, 0, 0}, + {0x3301, 0xd6, 0, 0}, {0x3302, 0xef, 0, 0}, {0x30b8, 0x20, 0, 0}, + {0x30b9, 0x17, 0, 0}, {0x30ba, 0x04, 0, 0}, {0x30bb, 0x08, 0, 0}, + {0x3100, 0x02, 0, 0}, {0x3304, 0x00, 0, 0}, {0x3400, 0x00, 0, 0}, + {0x3404, 0x02, 0, 0}, {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0}, + {0x3022, 0x00, 0, 0}, {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0}, + {0x3025, 0x18, 0, 0}, {0x3026, 0x06, 0, 0}, {0x3027, 0x0c, 0, 0}, + {0x335f, 0x68, 0, 0}, {0x3360, 0x18, 0, 0}, {0x3361, 0x0c, 0, 0}, + {0x3362, 0x68, 0, 0}, {0x3363, 0x08, 0, 0}, {0x3364, 0x04, 0, 0}, + {0x3403, 0x42, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0}, + {0x308a, 0x06, 0, 0}, {0x308b, 0x00, 0, 0}, {0x3507, 0x06, 0, 0}, + {0x350a, 0x4f, 0, 0}, {0x3600, 0xc4, 0, 0}, +#endif + /* + * Only support 7.5fps for QXGA to workaround screen tearing issue + * for 15fps when capturing still image. + */ {0x3012, 0x80, 0, 0}, {0x304d, 0x45, 0, 0}, {0x30a7, 0x5e, 0, 0}, {0x3087, 0x16, 0, 0}, {0x309c, 0x1a, 0, 0}, {0x30a2, 0xe4, 0, 0}, {0x30aa, 0x42, 0, 0}, {0x30b0, 0xff, 0, 0}, {0x30b1, 0xff, 0, 0}, @@ -118,25 +156,9 @@ static struct reg_value ov3640_setting_15fps_QXGA_2048_1536[] = { {0x30bb, 0x08, 0, 0}, {0x3507, 0x06, 0, 0}, {0x350a, 0x4f, 0, 0}, {0x3100, 0x02, 0, 0}, {0x3301, 0xde, 0, 0}, {0x3304, 0x00, 0, 0}, {0x3400, 0x00, 0, 0}, {0x3404, 0x02, 0, 0}, {0x3600, 0xc4, 0, 0}, - {0x3302, 0xef, 0, 0}, {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0}, - {0x3022, 0x00, 0, 0}, {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0}, - {0x3025, 0x00, 0, 0}, {0x3026, 0x06, 0, 0}, {0x3027, 0x00, 0, 0}, - {0x335f, 0x68, 0, 0}, {0x3360, 0x00, 0, 0}, {0x3361, 0x00, 0, 0}, - {0x3362, 0x68, 0, 0}, {0x3363, 0x00, 0, 0}, {0x3364, 0x00, 0, 0}, - {0x3403, 0x00, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0}, - {0x308a, 0x06, 0, 0}, {0x308b, 0x00, 0, 0}, {0x307c, 0x10, 0, 0}, - {0x3090, 0xc0, 0, 0}, {0x304c, 0x84, 0, 0}, {0x308d, 0x04, 0, 0}, - {0x3086, 0x03, 0, 0}, {0x3086, 0x00, 0, 0}, {0x3012, 0x00, 0, 0}, - {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0}, {0x3022, 0x00, 0, 0}, - {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0}, {0x3025, 0x18, 0, 0}, - {0x3026, 0x06, 0, 0}, {0x3027, 0x0c, 0, 0}, {0x302a, 0x06, 0, 0}, - {0x302b, 0x20, 0, 0}, {0x3075, 0x44, 0, 0}, {0x300d, 0x00, 0, 0}, - {0x30d7, 0x00, 0, 0}, {0x3069, 0x40, 0, 0}, {0x303e, 0x01, 0, 0}, - {0x303f, 0x80, 0, 0}, {0x3302, 0x20, 0, 0}, {0x335f, 0x68, 0, 0}, - {0x3360, 0x18, 0, 0}, {0x3361, 0x0c, 0, 0}, {0x3362, 0x68, 0, 0}, - {0x3363, 0x08, 0, 0}, {0x3364, 0x04, 0, 0}, {0x3403, 0x42, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0}, {0x308a, 0x06, 0, 0}, - {0x308b, 0x00, 0, 0}, + {0x308b, 0x00, 0, 0}, {0x308d, 0x04, 0, 0}, {0x3086, 0x03, 0, 0}, + {0x3086, 0x00, 0, 0}, {0x3011, 0x01, 0, 0}, }; static struct reg_value ov3640_setting_15fps_XGA_1024_768[] = { @@ -674,6 +696,7 @@ static struct regulator *io_regulator; static struct regulator *core_regulator; static struct regulator *analog_regulator; static struct regulator *gpo_regulator; +static struct mxc_camera_platform_data *camera_plat; static int ov3640_probe(struct i2c_client *adapter, const struct i2c_device_id *device_id); @@ -843,6 +866,10 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) if (analog_regulator) if (regulator_enable(analog_regulator) != 0) return -EIO; + /* Make sure power on */ + if (camera_plat->pwdn) + camera_plat->pwdn(0); + } else if (!on && sensor->on) { if (analog_regulator) regulator_disable(analog_regulator); @@ -920,6 +947,10 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) enum ov3640_frame_rate frame_rate; int ret = 0; + /* Make sure power on */ + if (camera_plat->pwdn) + camera_plat->pwdn(0); + switch (a->type) { /* This is the only case currently handled. */ case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -1286,17 +1317,25 @@ static int ov3640_probe(struct i2c_client *client, gpo_regulator = regulator_get(&client->dev, plat_data->gpo_regulator); if (!IS_ERR(gpo_regulator)) { + regulator_set_voltage(gpo_regulator, + OV3640_VOLTAGE_DIGITAL_GPO, + OV3640_VOLTAGE_DIGITAL_GPO); if (regulator_enable(gpo_regulator) != 0) { - pr_err("%s:gpo3 enable error\n", __func__); + pr_err("%s:gpo enable error\n", __func__); goto err4; } else { dev_dbg(&client->dev, - "%s:gpo3 enable ok\n", __func__); + "%s:gpo enable ok\n", __func__); } } else gpo_regulator = NULL; } + if (plat_data->pwdn) + plat_data->pwdn(0); + + camera_plat = plat_data; + ov3640_int_device.priv = &ov3640_data; retval = v4l2_int_device_register(&ov3640_int_device); |