diff options
Diffstat (limited to 'drivers/media/video/mxc/capture')
-rw-r--r-- | drivers/media/video/mxc/capture/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/csi_v4l2_capture.c | 223 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/fsl_csi.c | 58 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/fsl_csi.h | 35 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mt9v111.c | 4 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mxc_v4l2_capture.h | 18 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/ov2640.c | 4 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/sensor_clock.c | 28 |
8 files changed, 308 insertions, 64 deletions
diff --git a/drivers/media/video/mxc/capture/Kconfig b/drivers/media/video/mxc/capture/Kconfig index a7b14cb23b9b..febe9d874fb8 100644 --- a/drivers/media/video/mxc/capture/Kconfig +++ b/drivers/media/video/mxc/capture/Kconfig @@ -13,7 +13,7 @@ config VIDEO_MXC_EMMA_CAMERA default y config VIDEO_MXC_CSI_CAMERA - tristate "MX25 CSI camera support" + tristate "CSI camera support" depends on !VIDEO_MXC_EMMA_CAMERA config VIDEO_MXC_CSI_DMA diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c index eb824ddf5eb3..ada6d5e8afbd 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-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -15,7 +15,7 @@ * @file drivers/media/video/mxc/capture/csi_v4l2_capture.c * This file is derived from mxc_v4l2_capture.c * - * @brief MX25 Video For Linux 2 driver + * @brief Video For Linux 2 capture driver * * @ingroup MXC_V4L2_CAPTURE */ @@ -61,6 +61,198 @@ static struct v4l2_int_device csi_v4l2_int_device = { }, }; +/* Callback function triggered after PxP receives an EOF interrupt */ +static void pxp_dma_done(void *arg) +{ + struct pxp_tx_desc *tx_desc = to_tx_desc(arg); + struct dma_chan *chan = tx_desc->txd.chan; + struct pxp_channel *pxp_chan = to_pxp_channel(chan); + cam_data *cam = pxp_chan->client; + + /* This call will signal wait_for_completion_timeout() */ + complete(&cam->pxp_tx_cmpl); +} + +static bool chan_filter(struct dma_chan *chan, void *arg) +{ + if (imx_dma_is_pxp(chan)) + return true; + else + return false; +} + +/* Function to request PXP DMA channel */ +static int pxp_chan_init(cam_data *cam) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + + /* Request a free channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_PRIVATE, mask); + chan = dma_request_channel(mask, chan_filter, NULL); + if (!chan) { + pr_err("Unsuccessfully request channel!\n"); + return -EBUSY; + } + + cam->pxp_chan = to_pxp_channel(chan); + cam->pxp_chan->client = cam; + + init_completion(&cam->pxp_tx_cmpl); + + return 0; +} + +/* + * Function to call PxP DMA driver and send our new V4L2 buffer + * through the PxP and PxP will process this buffer in place. + * Note: This is a blocking call, so upon return the PxP tx should be complete. + */ +static int pxp_process_update(cam_data *cam) +{ + dma_cookie_t cookie; + struct scatterlist *sg = cam->sg; + struct dma_chan *dma_chan; + struct pxp_tx_desc *desc; + struct dma_async_tx_descriptor *txd; + struct pxp_config_data *pxp_conf = &cam->pxp_conf; + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + int i, ret; + int length; + + pr_debug("Starting PxP Send Buffer\n"); + + /* First, check to see that we have acquired a PxP Channel object */ + if (cam->pxp_chan == NULL) { + /* + * PxP Channel has not yet been created and initialized, + * so let's go ahead and try + */ + ret = pxp_chan_init(cam); + if (ret) { + /* + * PxP channel init failed, and we can't use the + * PxP until the PxP DMA driver has loaded, so we abort + */ + pr_err("PxP chan init failed\n"); + return -ENODEV; + } + } + + /* + * Init completion, so that we can be properly informed of + * the completion of the PxP task when it is done. + */ + init_completion(&cam->pxp_tx_cmpl); + + dma_chan = &cam->pxp_chan->dma_chan; + + txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2, + DMA_TO_DEVICE, + DMA_PREP_INTERRUPT); + if (!txd) { + pr_err("Error preparing a DMA transaction descriptor.\n"); + return -EIO; + } + + txd->callback_param = txd; + txd->callback = pxp_dma_done; + + /* + * Configure PxP for processing of new v4l2 buf + */ + pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_UYVY; + pxp_conf->s0_param.color_key = -1; + pxp_conf->s0_param.color_key_enable = false; + pxp_conf->s0_param.width = cam->v2f.fmt.pix.width; + pxp_conf->s0_param.height = cam->v2f.fmt.pix.height; + + pxp_conf->ol_param[0].combine_enable = false; + + proc_data->srect.top = 0; + proc_data->srect.left = 0; + proc_data->srect.width = pxp_conf->s0_param.width; + proc_data->srect.height = pxp_conf->s0_param.height; + + proc_data->drect.top = 0; + proc_data->drect.left = 0; + proc_data->drect.width = proc_data->srect.width; + proc_data->drect.height = proc_data->srect.height; + proc_data->scaling = 0; + proc_data->hflip = 0; + proc_data->vflip = 0; + proc_data->rotate = 0; + proc_data->bgcolor = 0; + + pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565; + pxp_conf->out_param.width = proc_data->drect.width; + pxp_conf->out_param.height = proc_data->drect.height; + + if (cam->rotation >= IPU_ROTATE_90_RIGHT) + pxp_conf->out_param.stride = pxp_conf->out_param.height; + else + pxp_conf->out_param.stride = pxp_conf->out_param.width; + + desc = to_tx_desc(txd); + length = desc->len; + for (i = 0; i < length; i++) { + if (i == 0) {/* S0 */ + memcpy(&desc->proc_data, proc_data, + sizeof(struct pxp_proc_data)); + pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]); + memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param, + sizeof(struct pxp_layer_param)); + } else if (i == 1) { + pxp_conf->out_param.paddr = sg_dma_address(&sg[1]); + memcpy(&desc->layer_param.out_param, + &pxp_conf->out_param, + sizeof(struct pxp_layer_param)); + } + + desc = desc->next; + } + + /* Submitting our TX starts the PxP processing task */ + cookie = txd->tx_submit(txd); + if (cookie < 0) { + pr_err("Error sending FB through PxP\n"); + return -EIO; + } + + cam->txd = txd; + + /* trigger PxP */ + dma_async_issue_pending(dma_chan); + + return 0; +} + +static int pxp_complete_update(cam_data *cam) +{ + int ret; + /* + * Wait for completion event, which will be set + * through our TX callback function. + */ + ret = wait_for_completion_timeout(&cam->pxp_tx_cmpl, HZ / 10); + if (ret <= 0) { + pr_warning("PxP operation failed due to %s\n", + ret < 0 ? "user interrupt" : "timeout"); + dma_release_channel(&cam->pxp_chan->dma_chan); + cam->pxp_chan = NULL; + return ret ? : -ETIMEDOUT; + } + + dma_release_channel(&cam->pxp_chan->dma_chan); + cam->pxp_chan = NULL; + + pr_debug("TX completed\n"); + + return 0; +} + /*! * Camera V4l2 callback function. * @@ -666,6 +858,23 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) buf->flags = frame->buffer.flags; buf->m = cam->frame[frame->index].buffer.m; + /* + * Note: + * If want to do preview on LCD, use PxP CSC to convert from UYVY + * to RGB565; but for encoding, usually we don't use RGB format. + */ + if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { + /* PxP processes it in place */ + sg_dma_address(&cam->sg[0]) = buf->m.offset; + sg_dma_address(&cam->sg[1]) = buf->m.offset; + retval = pxp_process_update(cam); + if (retval) { + pr_err("Unable to submit PxP update task.\n"); + return retval; + } + pxp_complete_update(cam); + } + return retval; } @@ -1186,8 +1395,8 @@ static void init_camera_struct(cam_data *cam) /* Default everything to 0 */ memset(cam, 0, sizeof(cam_data)); - init_MUTEX(&cam->param_lock); - init_MUTEX(&cam->busy_lock); + sema_init(&cam->param_lock, 1); + sema_init(&cam->busy_lock, 1); cam->video_dev = video_device_alloc(); if (cam->video_dev == NULL) @@ -1382,6 +1591,7 @@ static void csi_v4l2_master_detach(struct v4l2_int_device *slave) */ static __init int camera_init(void) { + struct scatterlist *sg; u8 err = 0; /* Register the device driver structure. */ @@ -1430,6 +1640,11 @@ static __init int camera_init(void) pr_debug(" Video device registered: %s #%d\n", g_cam->video_dev->name, g_cam->video_dev->minor); + g_cam->pxp_chan = NULL; + /* Initialize Scatter-gather list containing 2 buffer addresses. */ + sg = g_cam->sg; + sg_init_table(sg, 2); + return err; } diff --git a/drivers/media/video/mxc/capture/fsl_csi.c b/drivers/media/video/mxc/capture/fsl_csi.c index dba35c4499e2..33a82242e95e 100644 --- a/drivers/media/video/mxc/capture/fsl_csi.c +++ b/drivers/media/video/mxc/capture/fsl_csi.c @@ -1,5 +1,5 @@ /* - * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -20,6 +20,7 @@ */ #include <linux/types.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/device.h> #include <linux/err.h> #include <linux/interrupt.h> @@ -27,11 +28,14 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/clk.h> +#include <linux/sched.h> #include <mach/clock.h> #include "mxc_v4l2_capture.h" #include "fsl_csi.h" +void __iomem *csi_regbase; +static int irq_nr; static bool g_csi_mclk_on; static csi_irq_callback_t g_callback; static void *g_callback_data; @@ -164,7 +168,7 @@ void csi_start_callback(void *data) { cam_data *cam = (cam_data *) data; - if (request_irq(MXC_INT_CSI, csi_irq_handler, 0, "csi", cam) < 0) + if (request_irq(irq_nr, csi_irq_handler, 0, "csi", cam) < 0) pr_debug("CSI error: irq request fail\n"); } @@ -174,7 +178,7 @@ void csi_stop_callback(void *data) { cam_data *cam = (cam_data *) data; - free_irq(MXC_INT_CSI, cam); + free_irq(irq_nr, cam); } EXPORT_SYMBOL(csi_stop_callback); @@ -254,10 +258,32 @@ void csi_mclk_disable(void) __raw_writel(__raw_readl(CSI_CSICR1) & ~BIT_MCLKEN, CSI_CSICR1); } -int32_t __init csi_init_module(void) +static int __devinit csi_probe(struct platform_device *pdev) { int ret = 0; struct clk *per_clk; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "No csi irq found.\n"); + ret = -ENODEV; + goto err; + } + irq_nr = res->start; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "No csi base address found.\n"); + ret = -ENODEV; + goto err; + } + csi_regbase = ioremap(res->start, resource_size(res)); + if (!csi_regbase) { + dev_err(&pdev->dev, "ioremap failed with csi base\n"); + ret = -ENOMEM; + goto err; + } csihw_reset(); csi_init_interface(); @@ -271,12 +297,34 @@ int32_t __init csi_init_module(void) clk_enable(per_clk); csi_mclk_recalc(&csi_mclk); +err: return ret; } -void __exit csi_cleanup_module(void) +static int __devexit csi_remove(struct platform_device *pdev) { clk_disable(&csi_mclk); + iounmap(csi_regbase); + + return 0; +} + +static struct platform_driver csi_driver = { + .driver = { + .name = "fsl_csi", + }, + .probe = csi_probe, + .remove = __devexit_p(csi_remove), +}; + +int32_t __init csi_init_module(void) +{ + return platform_driver_register(&csi_driver); +} + +void __exit csi_cleanup_module(void) +{ + platform_driver_unregister(&csi_driver); } module_init(csi_init_module); diff --git a/drivers/media/video/mxc/capture/fsl_csi.h b/drivers/media/video/mxc/capture/fsl_csi.h index 00c389892224..8dfce286fe53 100644 --- a/drivers/media/video/mxc/capture/fsl_csi.h +++ b/drivers/media/video/mxc/capture/fsl_csi.h @@ -1,5 +1,5 @@ /* - * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -102,23 +102,22 @@ #define CSI_MCLK_I2C 8 #endif -#define CSI_CSICR1 (IO_ADDRESS(CSI_BASE_ADDR)) -#define CSI_CSICR2 (IO_ADDRESS(CSI_BASE_ADDR + 0x4)) -#define CSI_CSICR3 (IO_ADDRESS(CSI_BASE_ADDR + 0x8)) -#define CSI_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0xC)) -#define CSI_CSIRXFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x10)) -#define CSI_CSIRXCNT (IO_ADDRESS(CSI_BASE_ADDR + 0x14)) -#define CSI_CSISR (IO_ADDRESS(CSI_BASE_ADDR + 0x18)) - -#define CSI_CSIDBG (IO_ADDRESS(CSI_BASE_ADDR + 0x1C)) -#define CSI_CSIDMASA_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x20)) -#define CSI_CSIDMATS_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x24)) -#define CSI_CSIDMASA_FB1 (IO_ADDRESS(CSI_BASE_ADDR + 0x28)) -#define CSI_CSIDMASA_FB2 (IO_ADDRESS(CSI_BASE_ADDR + 0x2C)) -#define CSI_CSIFBUF_PARA (IO_ADDRESS(CSI_BASE_ADDR + 0x30)) -#define CSI_CSIIMAG_PARA (IO_ADDRESS(CSI_BASE_ADDR + 0x34)) - -#define CSI_CSIRXFIFO_PHYADDR (CSI_BASE_ADDR + 0x10) +extern void __iomem *csi_regbase; +#define CSI_CSICR1 (csi_regbase) +#define CSI_CSICR2 (csi_regbase + 0x4) +#define CSI_CSICR3 (csi_regbase + 0x8) +#define CSI_STATFIFO (csi_regbase + 0xC) +#define CSI_CSIRXFIFO (csi_regbase + 0x10) +#define CSI_CSIRXCNT (csi_regbase + 0x14) +#define CSI_CSISR (csi_regbase + 0x18) + +#define CSI_CSIDBG (csi_regbase + 0x1C) +#define CSI_CSIDMASA_STATFIFO (csi_regbase + 0x20) +#define CSI_CSIDMATS_STATFIFO (csi_regbase + 0x24) +#define CSI_CSIDMASA_FB1 (csi_regbase + 0x28) +#define CSI_CSIDMASA_FB2 (csi_regbase + 0x2C) +#define CSI_CSIFBUF_PARA (csi_regbase + 0x30) +#define CSI_CSIIMAG_PARA (csi_regbase + 0x34) static inline void csi_clear_status(unsigned long status) { diff --git a/drivers/media/video/mxc/capture/mt9v111.c b/drivers/media/video/mxc/capture/mt9v111.c index 4305c56c82d9..3ae65db04486 100644 --- a/drivers/media/video/mxc/capture/mt9v111.c +++ b/drivers/media/video/mxc/capture/mt9v111.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -879,7 +879,7 @@ static int ioctl_dev_init(struct v4l2_int_device *s) gpio_sensor_active(); - set_mclk_rate(&clock_rate); + set_mclk_rate(&clock_rate, 0); mt9v111_rate_cal(&reset_frame_rate, clock_rate); mt9v111_sensor_lib(mt9v111_device.coreReg, mt9v111_device.ifpReg); diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h index 27f8a78a93b3..034fd168290f 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h @@ -31,6 +31,10 @@ #include <linux/list.h> #include <linux/ipu.h> #include <linux/mxc_v4l2.h> +#include <linux/completion.h> +#include <linux/dmaengine.h> +#include <linux/pxp_dma.h> +#include <mach/dma.h> #include <mach/ipu-v3.h> #include <media/v4l2-dev.h> @@ -205,6 +209,14 @@ typedef struct _cam_data { struct v4l2_int_device *self; int sensor_index; void *ipu; + + /* v4l2 buf elements related to PxP DMA */ + struct completion pxp_tx_cmpl; + struct pxp_channel *pxp_chan; + struct pxp_config_data pxp_conf; + struct dma_async_tx_descriptor *txd; + dma_cookie_t cookie; + struct scatterlist sg[2]; } cam_data; struct sensor_data { @@ -232,11 +244,5 @@ struct sensor_data { void (*io_init)(void); }; -#if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA_MODULE) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA) -void set_mclk_rate(uint32_t *p_mclk_freq); -#else void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi); -#endif #endif /* __MXC_V4L2_CAPTURE_H__ */ diff --git a/drivers/media/video/mxc/capture/ov2640.c b/drivers/media/video/mxc/capture/ov2640.c index a0a050bca2e9..24ebd5027ff1 100644 --- a/drivers/media/video/mxc/capture/ov2640.c +++ b/drivers/media/video/mxc/capture/ov2640.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -801,7 +801,7 @@ static int ioctl_dev_init(struct v4l2_int_device *s) pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); - set_mclk_rate(&ov2640_data.mclk); + set_mclk_rate(&ov2640_data.mclk, 0); return ov2640_init_mode(sensor); } diff --git a/drivers/media/video/mxc/capture/sensor_clock.c b/drivers/media/video/mxc/capture/sensor_clock.c index 8004aeee5dc2..150659fa5dc0 100644 --- a/drivers/media/video/mxc/capture/sensor_clock.c +++ b/drivers/media/video/mxc/capture/sensor_clock.c @@ -26,31 +26,6 @@ #include <mach/hardware.h> #include <asm/mach-types.h> -#if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA_MODULE) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA) -/* - * set_mclk_rate - * - * @param p_mclk_freq mclk frequence - * - */ -void set_mclk_rate(uint32_t *p_mclk_freq) -{ - struct clk *clk; - uint32_t freq = 0; - - clk = clk_get(NULL, "csi_clk"); - - freq = clk_round_rate(clk, *p_mclk_freq); - clk_set_rate(clk, freq); - - *p_mclk_freq = freq; - - clk_put(clk); - pr_debug("mclk frequency = %d\n", *p_mclk_freq); -} -#else /* * set_mclk_rate * @@ -81,6 +56,8 @@ void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi) pr_err("invalid csi num %d\n", csi); return; }; + } else if (cpu_is_mx25() || cpu_is_mx6sl()) { /* only has CSI0 */ + mclk = "csi_clk"; } else { if (csi == 0) { mclk = "csi_mclk1"; @@ -102,7 +79,6 @@ void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi) clk_put(clk); pr_debug("%s frequency = %d\n", mclk, *p_mclk_freq); } -#endif /* Exported symbols for modules. */ EXPORT_SYMBOL(set_mclk_rate); |