12066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/*
22066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * V4L2 Driver for i.MX27/i.MX25 camera host
32066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach *
42066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * Copyright (C) 2008, Sascha Hauer, Pengutronix
52066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
62066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach *
72066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * This program is free software; you can redistribute it and/or modify
82066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * it under the terms of the GNU General Public License as published by
92066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * the Free Software Foundation; either version 2 of the License, or
102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * (at your option) any later version.
112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach */
122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/init.h>
142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/module.h>
152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/io.h>
162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/delay.h>
172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/slab.h>
182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/dma-mapping.h>
192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/errno.h>
202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/fs.h>
212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/interrupt.h>
222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/kernel.h>
232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/mm.h>
242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/moduleparam.h>
252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/time.h>
262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/device.h>
272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/platform_device.h>
282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/mutex.h>
292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/clk.h>
302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <media/v4l2-common.h>
322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <media/v4l2-dev.h>
336b101926f98b54549128db4d34f4a73b5f03feccSascha Hauer#include <media/videobuf-core.h>
342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <media/videobuf-dma-contig.h>
352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <media/soc_camera.h>
362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <media/soc_mediabus.h>
372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <linux/videodev2.h>
392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <mach/mx2_cam.h>
412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef CONFIG_MACH_MX27
422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <mach/dma-mx1-mx2.h>
432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif
442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <mach/hardware.h>
452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#include <asm/dma.h>
472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define MX2_CAM_DRV_NAME "mx2-camera"
4964dc3c1a906467d90c24913b0b38dd13d9378f4fMauro Carvalho Chehab#define MX2_CAM_VERSION "0.0.6"
502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/* reset values */
532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_RESET_VAL	0x40000800
542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR2_RESET_VAL	0x0
552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_RESET_VAL	0x0
562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/* csi control reg 1 */
582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_SWAP16_EN	(1 << 31)
592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_EXT_VSYNC	(1 << 30)
602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_EOF_INTEN	(1 << 29)
612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_PRP_IF_EN	(1 << 28)
622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_CCIR_MODE	(1 << 27)
632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_COF_INTEN	(1 << 26)
642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_SF_OR_INTEN	(1 << 25)
652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_RF_OR_INTEN	(1 << 24)
662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_STATFF_LEVEL	(3 << 22)
672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_STATFF_INTEN	(1 << 21)
682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_RXFF_LEVEL(l)	(((l) & 3) << 19)	/* MX27 */
692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_FB2_DMA_INTEN	(1 << 20)		/* MX25 */
702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_FB1_DMA_INTEN	(1 << 19)		/* MX25 */
712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_RXFF_INTEN	(1 << 18)
722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_SOF_POL		(1 << 17)
732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_SOF_INTEN	(1 << 16)
742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_MCLKDIV(d)	(((d) & 0xF) << 12)
752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_HSYNC_POL	(1 << 11)
762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_CCIR_EN		(1 << 10)
772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_MCLKEN		(1 << 9)
782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_FCC		(1 << 8)
792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_PACK_DIR		(1 << 7)
802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_CLR_STATFIFO	(1 << 6)
812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_CLR_RXFIFO	(1 << 5)
822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_GCLK_MODE	(1 << 4)
832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_INV_DATA		(1 << 3)
842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_INV_PCLK		(1 << 2)
852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1_REDGE		(1 << 1)
862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define SHIFT_STATFF_LEVEL	22
882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define SHIFT_RXFF_LEVEL	19
892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define SHIFT_MCLKDIV		12
902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/* control reg 3 */
922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_FRMCNT		(0xFFFF << 16)
932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_FRMCNT_RST	(1 << 15)
942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_DMA_REFLASH_RFF	(1 << 14)
952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_DMA_REFLASH_SFF	(1 << 13)
962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_DMA_REQ_EN_RFF	(1 << 12)
972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_DMA_REQ_EN_SFF	(1 << 11)
982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_RXFF_LEVEL(l)	(((l) & 7) << 4)	/* MX25 */
992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_CSI_SUP		(1 << 3)
1002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_ZERO_PACK_EN	(1 << 2)
1012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_ECC_INT_EN	(1 << 1)
1022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3_ECC_AUTO_EN	(1 << 0)
1032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define SHIFT_FRMCNT		16
1052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/* csi status reg */
1072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_SFF_OR_INT	(1 << 25)
1082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_RFF_OR_INT	(1 << 24)
1092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_STATFF_INT	(1 << 21)
1102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_DMA_TSF_FB2_INT	(1 << 20)	/* MX25 */
1112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_DMA_TSF_FB1_INT	(1 << 19)	/* MX25 */
1122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_RXFF_INT		(1 << 18)
1132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_EOF_INT		(1 << 17)
1142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_SOF_INT		(1 << 16)
1152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_F2_INT		(1 << 15)
1162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_F1_INT		(1 << 14)
1172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_COF_INT		(1 << 13)
1182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_ECC_INT		(1 << 1)
1192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR_DRDY		(1 << 0)
1202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR1			0x00
1222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR2			0x04
1232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISR			(cpu_is_mx27() ? 0x08 : 0x18)
1242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSISTATFIFO		0x0c
1252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIRFIFO		0x10
1262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIRXCNT		0x14
1272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSICR3			(cpu_is_mx27() ? 0x1C : 0x08)
1282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIDMASA_STATFIFO	0x20
1292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIDMATA_STATFIFO	0x24
1302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIDMASA_FB1		0x28
1312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIDMASA_FB2		0x2c
1322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIFBUF_PARA		0x30
1332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define CSIIMAG_PARA		0x34
1342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/* EMMA PrP */
1362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL			0x00
1372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_CNTL			0x04
1382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTRSTATUS			0x08
1392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_SOURCE_Y_PTR		0x0c
1402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_SOURCE_CB_PTR		0x10
1412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_SOURCE_CR_PTR		0x14
1422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_DEST_RGB1_PTR		0x18
1432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_DEST_RGB2_PTR		0x1c
1442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_DEST_Y_PTR			0x20
1452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_DEST_CB_PTR			0x24
1462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_DEST_CR_PTR			0x28
1472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_SRC_FRAME_SIZE		0x2c
1482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_DEST_CH1_LINE_STRIDE	0x30
1492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_SRC_PIXEL_FORMAT_CNTL	0x34
1502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_PIXEL_FORMAT_CNTL	0x38
1512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_OUT_IMAGE_SIZE		0x3c
1522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH2_OUT_IMAGE_SIZE		0x40
1532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_SRC_LINE_STRIDE		0x44
1542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CSC_COEF_012		0x48
1552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CSC_COEF_345		0x4c
1562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CSC_COEF_678		0x50
1572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_RZ_HORI_COEF1		0x54
1582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_RZ_HORI_COEF2		0x58
1592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_RZ_HORI_VALID		0x5c
1602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_RZ_VERT_COEF1		0x60
1612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_RZ_VERT_COEF2		0x64
1622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH1_RZ_VERT_VALID		0x68
1632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH2_RZ_HORI_COEF1		0x6c
1642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH2_RZ_HORI_COEF2		0x70
1652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH2_RZ_HORI_VALID		0x74
1662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH2_RZ_VERT_COEF1		0x78
1672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH2_RZ_VERT_COEF2		0x7c
1682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CH2_RZ_VERT_VALID		0x80
1692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1EN		(1 << 0)
1712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2EN		(1 << 1)
1722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CSIEN		(1 << 2)
1732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_DATA_IN_YUV420	(0 << 3)
1742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_DATA_IN_YUV422	(1 << 3)
1752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_DATA_IN_RGB16	(2 << 3)
1762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_DATA_IN_RGB32	(3 << 3)
1772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1_OUT_RGB8	(0 << 5)
1782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1_OUT_RGB16	(1 << 5)
1792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1_OUT_RGB32	(2 << 5)
1802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1_OUT_YUV422	(3 << 5)
1812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2_OUT_YUV420	(0 << 7)
1822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
1832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2_OUT_YUV444	(2 << 7)
1842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1_LEN	(1 << 9)
1852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2_LEN	(1 << 10)
1862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_SKIP_FRAME	(1 << 11)
1872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_SWRST		(1 << 12)
1882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CLKEN		(1 << 13)
1892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_WEN		(1 << 14)
1902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1BYP		(1 << 15)
1912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_IN_TSKIP(x)	((x) << 16)
1922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH1_TSKIP(x)	((x) << 19)
1932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2_TSKIP(x)	((x) << 22)
1942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_INPUT_FIFO_LEVEL(x)	((x) << 25)
1952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_RZ_FIFO_LEVEL(x)	((x) << 27)
1962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2B1EN	(1 << 29)
1972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2B2EN	(1 << 30)
1982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_CNTL_CH2FEN		(1 << 31)
1992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/* IRQ Enable and status register */
2012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_RDERR		(1 << 0)
2022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_CH1WERR	(1 << 1)
2032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_CH2WERR	(1 << 2)
2042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_CH1FC		(1 << 3)
2052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_CH2FC		(1 << 5)
2062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_LBOVF		(1 << 7)
2072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define PRP_INTR_CH2OVF		(1 << 8)
2082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define mx27_camera_emma(pcdev)	(cpu_is_mx27() && pcdev->use_emma)
2102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define MAX_VIDEO_MEM	16
2122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
213f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martinstruct mx2_prp_cfg {
214f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	int channel;
215f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32 in_fmt;
216f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32 out_fmt;
217f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32 src_pixel;
218f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32 ch1_pixel;
219f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32 irq_flags;
220f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin};
221f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
222f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin/* prp configuration for a client-host fmt pair */
223f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martinstruct mx2_fmt_cfg {
224f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	enum v4l2_mbus_pixelcode	in_fmt;
225f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32				out_fmt;
226f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct mx2_prp_cfg		cfg;
227f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin};
228f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
2292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstruct mx2_camera_dev {
2302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct device		*dev;
2312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_host	soc_host;
2322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_device *icd;
2332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct clk		*clk_csi, *clk_emma;
2342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned int		irq_csi, irq_emma;
2362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	void __iomem		*base_csi, *base_emma;
2372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long		base_dma;
2382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_platform_data *pdata;
2402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct resource		*res_csi, *res_emma;
2412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long		platform_flags;
2422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct list_head	capture;
2442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct list_head	active_bufs;
2452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spinlock_t		lock;
2472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int			dma;
2492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer	*active;
2502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer	*fb1_active;
2512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer	*fb2_active;
2522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int			use_emma;
2542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32			csicr1;
2562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
25779d3c2c2395a89a70d25f0c77c11afc87efab89bBaruch Siach	void			*discard_buffer;
2582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	dma_addr_t		discard_buffer_dma;
2592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	size_t			discard_size;
260f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct mx2_fmt_cfg	*emma_prp;
261ccd1a499c1675fef5d2a138617507add63cb81dbJavier Martin	u32			frame_count;
2622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach};
2632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/* buffer for one video frame */
2652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstruct mx2_buffer {
2662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* common v4l buffer stuff -- must be first */
2672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct videobuf_buffer		vb;
2682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	enum v4l2_mbus_pixelcode	code;
2702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
2712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int bufnum;
2722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach};
2732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
274f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martinstatic struct mx2_fmt_cfg mx27_emma_prp_table[] = {
275f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	/*
276f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * This is a generic configuration which is valid for most
277f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * prp input-output format combinations.
278f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * We set the incomming and outgoing pixelformat to a
279f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * 16 Bit wide format and adjust the bytesperline
280f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * accordingly. With this configuration the inputdata
281f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * will not be changed by the emma and could be any type
282f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * of 16 Bit Pixelformat.
283f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 */
284f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	{
285f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		.in_fmt		= 0,
286f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		.out_fmt	= 0,
287f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		.cfg		= {
288f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.channel	= 1,
289f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.in_fmt		= PRP_CNTL_DATA_IN_RGB16,
290f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.out_fmt	= PRP_CNTL_CH1_OUT_RGB16,
291f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.src_pixel	= 0x2ca00565, /* RGB565 */
292f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.ch1_pixel	= 0x2ca00565, /* RGB565 */
293f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH1WERR |
294f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin						PRP_INTR_CH1FC | PRP_INTR_LBOVF,
295f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		}
296f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	},
297f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	{
298f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		.in_fmt		= V4L2_MBUS_FMT_YUYV8_2X8,
299f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		.out_fmt	= V4L2_PIX_FMT_YUV420,
300f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		.cfg		= {
301f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.channel	= 2,
302f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.in_fmt		= PRP_CNTL_DATA_IN_YUV422,
303f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.out_fmt	= PRP_CNTL_CH2_OUT_YUV420,
304f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.src_pixel	= 0x22000888, /* YUV422 (YUYV) */
305f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			.irq_flags	= PRP_INTR_RDERR | PRP_INTR_CH2WERR |
306f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin					PRP_INTR_CH2FC | PRP_INTR_LBOVF |
307f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin					PRP_INTR_CH2OVF,
308f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		}
309f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	},
310f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin};
311f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
312f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martinstatic struct mx2_fmt_cfg *mx27_emma_prp_get_format(
313f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin					enum v4l2_mbus_pixelcode in_fmt,
314f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin					u32 out_fmt)
315f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin{
316f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	int i;
317f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
318f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++)
319f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		if ((mx27_emma_prp_table[i].in_fmt == in_fmt) &&
320f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				(mx27_emma_prp_table[i].out_fmt == out_fmt)) {
321f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			return &mx27_emma_prp_table[i];
322f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		}
323f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	/* If no match return the most generic configuration */
324f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	return &mx27_emma_prp_table[0];
325f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin};
326f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
3272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
3282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
3292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long flags;
3302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	clk_disable(pcdev->clk_csi);
3322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(0, pcdev->base_csi + CSICR1);
3332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mx27_camera_emma(pcdev)) {
3342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel(0, pcdev->base_emma + PRP_CNTL);
3352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	} else if (cpu_is_mx25()) {
3362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		spin_lock_irqsave(&pcdev->lock, flags);
3372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->fb1_active = NULL;
3382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->fb2_active = NULL;
3392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel(0, pcdev->base_csi + CSIDMASA_FB1);
3402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel(0, pcdev->base_csi + CSIDMASA_FB2);
3412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		spin_unlock_irqrestore(&pcdev->lock, flags);
3422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
3432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
3442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/*
3462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * The following two functions absolutely depend on the fact, that
3472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach * there can be only one camera on mx2 camera sensor interface
3482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach */
3492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx2_camera_add_device(struct soc_camera_device *icd)
3502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
3517dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
3522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = ici->priv;
3532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int ret;
3542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32 csicr1;
3552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->icd)
3572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return -EBUSY;
3582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	ret = clk_enable(pcdev->clk_csi);
3602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (ret < 0)
3612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return ret;
3622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	csicr1 = CSICR1_MCLKEN;
3642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mx27_camera_emma(pcdev)) {
3662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
3672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			CSICR1_RXFF_LEVEL(0);
3682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	} else if (cpu_is_mx27())
3692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2);
3702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->csicr1 = csicr1;
3722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
3732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->icd = icd;
375ccd1a499c1675fef5d2a138617507add63cb81dbJavier Martin	pcdev->frame_count = 0;
3762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3777dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_info(icd->parent, "Camera driver attached to camera %d\n",
3782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 icd->devnum);
3792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
3812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
3822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx2_camera_remove_device(struct soc_camera_device *icd)
3842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
3857dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
3862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = ici->priv;
3872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	BUG_ON(icd != pcdev->icd);
3892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3907dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_info(icd->parent, "Camera driver detached from camera %d\n",
3912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 icd->devnum);
3922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mx2_camera_deactivate(pcdev);
3942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
3952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->discard_buffer) {
3962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size,
3972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pcdev->discard_buffer,
3982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pcdev->discard_buffer_dma);
3992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->discard_buffer = NULL;
4002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
4012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->icd = NULL;
4032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
4042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef CONFIG_MACH_MX27
4062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev)
4072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
4082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32 tmp;
4092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	imx_dma_enable(pcdev->dma);
4112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	tmp = readl(pcdev->base_csi + CSICR1);
4132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	tmp |= CSICR1_RF_OR_INTEN;
4142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(tmp, pcdev->base_csi + CSICR1);
4152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
4162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic irqreturn_t mx27_camera_irq(int irq_csi, void *data)
4182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
4192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = data;
4202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32 status = readl(pcdev->base_csi + CSISR);
4212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (status & CSISR_SOF_INT && pcdev->active) {
4232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		u32 tmp;
4242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		tmp = readl(pcdev->base_csi + CSICR1);
4262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1);
4272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mx27_camera_dma_enable(pcdev);
4282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
4292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR);
4312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return IRQ_HANDLED;
4332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
4342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#else
4352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic irqreturn_t mx27_camera_irq(int irq_csi, void *data)
4362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
4372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return IRQ_NONE;
4382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
4392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif /* CONFIG_MACH_MX27 */
4402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
4422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		int state)
4432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
4442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct videobuf_buffer *vb;
4452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer *buf;
4462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
4472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		&pcdev->fb2_active;
4482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2;
4492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long flags;
4502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_lock_irqsave(&pcdev->lock, flags);
4522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4535384a12b23160e11ff949a94172051476d308b66Baruch Siach	if (*fb_active == NULL)
4545384a12b23160e11ff949a94172051476d308b66Baruch Siach		goto out;
4555384a12b23160e11ff949a94172051476d308b66Baruch Siach
4562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb = &(*fb_active)->vb;
4572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
4582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb, vb->baddr, vb->bsize);
4592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->state = state;
4612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	do_gettimeofday(&vb->ts);
4622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->field_count++;
4632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	wake_up(&vb->done);
4652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (list_empty(&pcdev->capture)) {
4672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		buf = NULL;
4682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel(0, pcdev->base_csi + fb_reg);
4692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	} else {
4702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		buf = list_entry(pcdev->capture.next, struct mx2_buffer,
4712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				vb.queue);
4722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb = &buf->vb;
4732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		list_del(&vb->queue);
4742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->state = VIDEOBUF_ACTIVE;
4752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg);
4762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
4772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	*fb_active = buf;
4792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4805384a12b23160e11ff949a94172051476d308b66Baruch Siachout:
4812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_unlock_irqrestore(&pcdev->lock, flags);
4822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
4832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic irqreturn_t mx25_camera_irq(int irq_csi, void *data)
4852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
4862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = data;
4872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32 status = readl(pcdev->base_csi + CSISR);
4882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (status & CSISR_DMA_TSF_FB1_INT)
4902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE);
4912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	else if (status & CSISR_DMA_TSF_FB2_INT)
4922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE);
4932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* FIXME: handle CSISR_RFF_OR_INT */
4952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(status, pcdev->base_csi + CSISR);
4972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
4982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return IRQ_HANDLED;
4992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
5002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach/*
5022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach *  Videobuf operations
5032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach */
5042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
5052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			      unsigned int *size)
5062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
5072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_device *icd = vq->priv_data;
5082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
5092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			icd->current_fmt->host_fmt);
5102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5117dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
5122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (bytes_per_line < 0)
5142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return bytes_per_line;
5152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	*size = bytes_per_line * icd->user_height;
5172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (0 == *count)
5192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		*count = 32;
5202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
5212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		*count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
5222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
5242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
5252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
5272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
5282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_device *icd = vq->priv_data;
5292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct videobuf_buffer *vb = &buf->vb;
5302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5317dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
5322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb, vb->baddr, vb->bsize);
5332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/*
5352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 * This waits until this buffer is out of danger, i.e., until it is no
53688bfd0bd7f8343c3c2ff65fe4d3fc3aff6ecca7cBaruch Siach	 * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE
5372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 */
5380e0809a58869e3e422985f868ad5e0da1fc0ba85Hans Verkuil	videobuf_waiton(vq, vb, 0, 0);
5392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	videobuf_dma_contig_free(vq, vb);
5417dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_dbg(icd->parent, "%s freed\n", __func__);
5422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->state = VIDEOBUF_NEEDS_INIT;
5442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
5452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx2_videobuf_prepare(struct videobuf_queue *vq,
5472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		struct videobuf_buffer *vb, enum v4l2_field field)
5482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
5492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_device *icd = vq->priv_data;
5502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
5512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
5522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			icd->current_fmt->host_fmt);
5532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int ret = 0;
5542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5557dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
5562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb, vb->baddr, vb->bsize);
5572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (bytes_per_line < 0)
5592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return bytes_per_line;
5602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef DEBUG
5622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/*
5632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 * This can be useful if you want to see if we actually fill
5642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 * the buffer with something
5652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 */
5662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	memset((void *)vb->baddr, 0xaa, vb->bsize);
5672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif
5682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (buf->code	!= icd->current_fmt->code ||
5702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	    vb->width	!= icd->user_width ||
5712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	    vb->height	!= icd->user_height ||
5722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	    vb->field	!= field) {
5732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		buf->code	= icd->current_fmt->code;
5742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->width	= icd->user_width;
5752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->height	= icd->user_height;
5762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->field	= field;
5772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->state	= VIDEOBUF_NEEDS_INIT;
5782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
5792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->size = bytes_per_line * vb->height;
5812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (vb->baddr && vb->bsize < vb->size) {
5822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		ret = -EINVAL;
5832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto out;
5842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
5852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (vb->state == VIDEOBUF_NEEDS_INIT) {
5872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		ret = videobuf_iolock(vq, vb, NULL);
5882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (ret)
5892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			goto fail;
5902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->state = VIDEOBUF_PREPARED;
5922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
5932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
5952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
5962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachfail:
5972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	free_buffer(vq, buf);
5982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachout:
5992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return ret;
6002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
6012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx2_videobuf_queue(struct videobuf_queue *vq,
6032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			       struct videobuf_buffer *vb)
6042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
6052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_device *icd = vq->priv_data;
6062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_host *ici =
6077dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		to_soc_camera_host(icd->parent);
6082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = ici->priv;
6092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
6102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long flags;
6112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6127dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
6132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb, vb->baddr, vb->bsize);
6142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_lock_irqsave(&pcdev->lock, flags);
6162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->state = VIDEOBUF_QUEUED;
6182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	list_add_tail(&vb->queue, &pcdev->capture);
6192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mx27_camera_emma(pcdev)) {
6212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto out;
6222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef CONFIG_MACH_MX27
6232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	} else if (cpu_is_mx27()) {
6242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		int ret;
6252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pcdev->active == NULL) {
6272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			ret = imx_dma_setup_single(pcdev->dma,
6282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach					videobuf_to_dma_contig(vb), vb->size,
6292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach					(u32)pcdev->base_dma + 0x10,
6302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach					DMA_MODE_READ);
6312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			if (ret) {
6322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				vb->state = VIDEOBUF_ERROR;
6332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				wake_up(&vb->done);
6342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				goto out;
6352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			}
6362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			vb->state = VIDEOBUF_ACTIVE;
6382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->active = buf;
6392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		}
6402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif
6412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	} else { /* cpu_is_mx25() */
6422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		u32 csicr3, dma_inten = 0;
6432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pcdev->fb1_active == NULL) {
6452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			writel(videobuf_to_dma_contig(vb),
6462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach					pcdev->base_csi + CSIDMASA_FB1);
6472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->fb1_active = buf;
6482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			dma_inten = CSICR1_FB1_DMA_INTEN;
6492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		} else if (pcdev->fb2_active == NULL) {
6502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			writel(videobuf_to_dma_contig(vb),
6512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach					pcdev->base_csi + CSIDMASA_FB2);
6522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->fb2_active = buf;
6532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			dma_inten = CSICR1_FB2_DMA_INTEN;
6542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		}
6552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (dma_inten) {
6572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			list_del(&vb->queue);
6582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			vb->state = VIDEOBUF_ACTIVE;
6592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			csicr3 = readl(pcdev->base_csi + CSICR3);
6612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			/* Reflash DMA */
6632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
6642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach					pcdev->base_csi + CSICR3);
6652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			/* clear & enable interrupts */
6672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			writel(dma_inten, pcdev->base_csi + CSISR);
6682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->csicr1 |= dma_inten;
6692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
6702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			/* enable DMA */
6722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
6732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			writel(csicr3, pcdev->base_csi + CSICR3);
6742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		}
6752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
6762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachout:
6782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_unlock_irqrestore(&pcdev->lock, flags);
6792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
6802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx2_videobuf_release(struct videobuf_queue *vq,
6822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				 struct videobuf_buffer *vb)
6832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
6842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_device *icd = vq->priv_data;
6857dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
6862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = ici->priv;
6872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
6882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long flags;
6892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef DEBUG
6917dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
6922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb, vb->baddr, vb->bsize);
6932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
6942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	switch (vb->state) {
6952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	case VIDEOBUF_ACTIVE:
6967dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		dev_info(icd->parent, "%s (active)\n", __func__);
6972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		break;
6982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	case VIDEOBUF_QUEUED:
6997dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		dev_info(icd->parent, "%s (queued)\n", __func__);
7002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		break;
7012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	case VIDEOBUF_PREPARED:
7027dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		dev_info(icd->parent, "%s (prepared)\n", __func__);
7032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		break;
7042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	default:
7057dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		dev_info(icd->parent, "%s (unknown) %d\n", __func__,
7062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				vb->state);
7072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		break;
7082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
7092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif
7102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/*
7122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 * Terminate only queued but inactive buffers. Active buffers are
7132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 * released when they become inactive after videobuf_waiton().
7142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 *
7157c6b73197062180d51e9871982b083a651838992Baruch Siach	 * FIXME: implement forced termination of active buffers for mx27 and
7167c6b73197062180d51e9871982b083a651838992Baruch Siach	 * mx27 eMMA, so that the user won't get stuck in an uninterruptible
7177c6b73197062180d51e9871982b083a651838992Baruch Siach	 * state. This requires a specific handling for each of the these DMA
7187c6b73197062180d51e9871982b083a651838992Baruch Siach	 * types.
7192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 */
7202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_lock_irqsave(&pcdev->lock, flags);
7212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (vb->state == VIDEOBUF_QUEUED) {
7222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		list_del(&vb->queue);
7232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->state = VIDEOBUF_ERROR;
7247c6b73197062180d51e9871982b083a651838992Baruch Siach	} else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) {
7257c6b73197062180d51e9871982b083a651838992Baruch Siach		if (pcdev->fb1_active == buf) {
7267c6b73197062180d51e9871982b083a651838992Baruch Siach			pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
7277c6b73197062180d51e9871982b083a651838992Baruch Siach			writel(0, pcdev->base_csi + CSIDMASA_FB1);
7287c6b73197062180d51e9871982b083a651838992Baruch Siach			pcdev->fb1_active = NULL;
7297c6b73197062180d51e9871982b083a651838992Baruch Siach		} else if (pcdev->fb2_active == buf) {
7307c6b73197062180d51e9871982b083a651838992Baruch Siach			pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN;
7317c6b73197062180d51e9871982b083a651838992Baruch Siach			writel(0, pcdev->base_csi + CSIDMASA_FB2);
7327c6b73197062180d51e9871982b083a651838992Baruch Siach			pcdev->fb2_active = NULL;
7337c6b73197062180d51e9871982b083a651838992Baruch Siach		}
7347c6b73197062180d51e9871982b083a651838992Baruch Siach		writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
7357c6b73197062180d51e9871982b083a651838992Baruch Siach		vb->state = VIDEOBUF_ERROR;
7362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
7372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_unlock_irqrestore(&pcdev->lock, flags);
7382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	free_buffer(vq, buf);
7402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
7412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic struct videobuf_queue_ops mx2_videobuf_ops = {
7432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.buf_setup      = mx2_videobuf_setup,
7442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.buf_prepare    = mx2_videobuf_prepare,
7452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.buf_queue      = mx2_videobuf_queue,
7462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.buf_release    = mx2_videobuf_release,
7472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach};
7482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx2_camera_init_videobuf(struct videobuf_queue *q,
7502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			      struct soc_camera_device *icd)
7512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
7527dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
7532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = ici->priv;
7542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
7562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			&pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
757b6a633c18ba83c0c8e96759a31d356bfb77e2b5fGuennadi Liakhovetski			V4L2_FIELD_NONE, sizeof(struct mx2_buffer),
758b6a633c18ba83c0c8e96759a31d356bfb77e2b5fGuennadi Liakhovetski			icd, &icd->video_lock);
7592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
7602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
761db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski#define MX2_BUS_FLAGS	(V4L2_MBUS_MASTER | \
762db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
763db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_VSYNC_ACTIVE_LOW | \
764db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
765db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_HSYNC_ACTIVE_LOW | \
766db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_PCLK_SAMPLE_RISING | \
767db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_PCLK_SAMPLE_FALLING | \
768db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_DATA_ACTIVE_HIGH | \
769db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			V4L2_MBUS_DATA_ACTIVE_LOW)
7702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
7722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
7732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32 cntl;
7742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int count = 0;
7752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	cntl = readl(pcdev->base_emma + PRP_CNTL);
7772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
7782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	while (count++ < 100) {
7792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
7802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			return 0;
7812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		barrier();
7822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		udelay(1);
7832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
7842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return -ETIMEDOUT;
7862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
7872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
7882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
7892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		int bytesperline)
7902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
7912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_host *ici =
7927dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		to_soc_camera_host(icd->parent);
7932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = ici->priv;
794f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
795f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
796f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
797f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (prp->cfg.channel == 1) {
798f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(pcdev->discard_buffer_dma,
799f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				pcdev->base_emma + PRP_DEST_RGB1_PTR);
800f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(pcdev->discard_buffer_dma,
801f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				pcdev->base_emma + PRP_DEST_RGB2_PTR);
802f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
803f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(PRP_CNTL_CH1EN |
804f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				PRP_CNTL_CSIEN |
805f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				prp->cfg.in_fmt |
806f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				prp->cfg.out_fmt |
807f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				PRP_CNTL_CH1_LEN |
808f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				PRP_CNTL_CH1BYP |
809f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				PRP_CNTL_CH1_TSKIP(0) |
810f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				PRP_CNTL_IN_TSKIP(0),
811f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				pcdev->base_emma + PRP_CNTL);
812f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
813f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel((icd->user_width << 16) | icd->user_height,
814f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_SRC_FRAME_SIZE);
815f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel((icd->user_width << 16) | icd->user_height,
816f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
817f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(bytesperline,
818f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
819f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(prp->cfg.src_pixel,
820f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
821f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(prp->cfg.ch1_pixel,
822f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
823f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	} else { /* channel 2 */
824f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(pcdev->discard_buffer_dma,
825f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_DEST_Y_PTR);
826f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(pcdev->discard_buffer_dma,
827f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_SOURCE_Y_PTR);
828f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
829f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
830f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(pcdev->discard_buffer_dma + imgsize,
831f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				pcdev->base_emma + PRP_DEST_CB_PTR);
832f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
833f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				pcdev->base_emma + PRP_DEST_CR_PTR);
834f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(pcdev->discard_buffer_dma + imgsize,
835f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				pcdev->base_emma + PRP_SOURCE_CB_PTR);
836f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
837f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				pcdev->base_emma + PRP_SOURCE_CR_PTR);
838f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		}
8392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
840f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(PRP_CNTL_CH2EN |
8412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			PRP_CNTL_CSIEN |
842f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			prp->cfg.in_fmt |
843f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			prp->cfg.out_fmt |
844f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			PRP_CNTL_CH2_LEN |
845f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			PRP_CNTL_CH2_TSKIP(0) |
8462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			PRP_CNTL_IN_TSKIP(0),
8472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->base_emma + PRP_CNTL);
8482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
849f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel((icd->user_width << 16) | icd->user_height,
8502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->base_emma + PRP_SRC_FRAME_SIZE);
851f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
852f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel((icd->user_width << 16) | icd->user_height,
853f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
854f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
855f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(prp->cfg.src_pixel,
8562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
857f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
858f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	}
8592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
8602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* Enable interrupts */
861f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
8622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
8632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
8648843d119eaf1a7a87a2cf8c3eadbd1937b16bc27Guennadi Liakhovetskistatic int mx2_camera_set_bus_param(struct soc_camera_device *icd)
8652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
866db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
867db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
8682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = ici->priv;
869db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
870db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	unsigned long common_flags;
871db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	int ret;
8722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int bytesperline;
8732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	u32 csicr1 = pcdev->csicr1;
8742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
875db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
876db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	if (!ret) {
877db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski		common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS);
878db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski		if (!common_flags) {
879db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			dev_warn(icd->parent,
880db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski				 "Flags incompatible: camera 0x%x, host 0x%x\n",
881db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski				 cfg.flags, MX2_BUS_FLAGS);
882db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			return -EINVAL;
883db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski		}
884db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	} else if (ret != -ENOIOCTLCMD) {
885db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski		return ret;
886db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	} else {
887db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski		common_flags = MX2_BUS_FLAGS;
888db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	}
8892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
890db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
891db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	    (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
8922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH)
893db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
8942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		else
895db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
8962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
8972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
898db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
899db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	    (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
9002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING)
901db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
9022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		else
903db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
9042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
9052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
906db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	cfg.flags = common_flags;
907db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
908db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	if (ret < 0 && ret != -ENOIOCTLCMD) {
909db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski		dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
910db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski			common_flags, ret);
9112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return ret;
912db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	}
9132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
914db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
915d86097e19cef2f13a29fc37db0dad17b99b6d5f8Michael Grzeschik		csicr1 |= CSICR1_REDGE;
916db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
9172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_SOF_POL;
918db592a24656ec1028728eb4eccc450b925bea268Guennadi Liakhovetski	if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
9192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_HSYNC_POL;
9202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
9212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_SWAP16_EN;
9222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
9232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_EXT_VSYNC;
9242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->platform_flags & MX2_CAMERA_CCIR)
9252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_CCIR_EN;
9262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE)
9272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_CCIR_MODE;
9282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK)
9292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_GCLK_MODE;
9302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
9312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_INV_DATA;
9322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
9332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		csicr1 |= CSICR1_PACK_DIR;
9342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->csicr1 = csicr1;
9362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	bytesperline = soc_mbus_bytes_per_line(icd->user_width,
9382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			icd->current_fmt->host_fmt);
9392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (bytesperline < 0)
9402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return bytesperline;
9412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mx27_camera_emma(pcdev)) {
9432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		ret = mx27_camera_emma_prp_reset(pcdev);
9442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (ret)
9452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			return ret;
9462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pcdev->discard_buffer)
9482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			dma_free_coherent(ici->v4l2_dev.dev,
9492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pcdev->discard_size, pcdev->discard_buffer,
9502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pcdev->discard_buffer_dma);
9512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		/*
9532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * I didn't manage to properly enable/disable the prp
9542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * on a per frame basis during running transfers,
9552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * thus we allocate a buffer here and use it to
9562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * discard frames when no buffer is available.
9572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * Feel free to work on this ;)
9582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 */
9592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->discard_size = icd->user_height * bytesperline;
9602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
9612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pcdev->discard_size, &pcdev->discard_buffer_dma,
9622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				GFP_KERNEL);
9632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (!pcdev->discard_buffer)
9642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			return -ENOMEM;
9652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mx27_camera_emma_buf_init(icd, bytesperline);
9672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	} else if (cpu_is_mx25()) {
9682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel((bytesperline * icd->user_height) >> 2,
9692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pcdev->base_csi + CSIRXCNT);
9702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel((bytesperline << 16) | icd->user_height,
9712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pcdev->base_csi + CSIIMAG_PARA);
9722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
9732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
9752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
9772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
9782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx2_camera_set_crop(struct soc_camera_device *icd,
9802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				struct v4l2_crop *a)
9812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
9822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_rect *rect = &a->c;
9832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
9842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_mbus_framefmt mf;
9852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int ret;
9862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
9882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
9892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	ret = v4l2_subdev_call(sd, video, s_crop, a);
9912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (ret < 0)
9922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return ret;
9932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* The capture device might have changed its output  */
9952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
9962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (ret < 0)
9972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return ret;
9982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
9997dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski	dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
10002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mf.width, mf.height);
10012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	icd->user_width		= mf.width;
10032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	icd->user_height	= mf.height;
10042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return ret;
10062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
10072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1008f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martinstatic int mx2_camera_get_formats(struct soc_camera_device *icd,
1009f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				  unsigned int idx,
1010f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				  struct soc_camera_format_xlate *xlate)
1011f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin{
1012f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1013f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	const struct soc_mbus_pixelfmt *fmt;
1014f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct device *dev = icd->parent;
1015f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	enum v4l2_mbus_pixelcode code;
1016f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	int ret, formats = 0;
1017f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
1018f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
1019f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (ret < 0)
1020f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		/* no more formats */
1021f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		return 0;
1022f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
1023f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	fmt = soc_mbus_get_fmtdesc(code);
1024f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (!fmt) {
1025f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
1026f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		return 0;
1027f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	}
1028f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
1029f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
1030f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		formats++;
1031f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		if (xlate) {
1032f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			/*
1033f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			 * CH2 can output YUV420 which is a standard format in
1034f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			 * soc_mediabus.c
1035f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			 */
1036f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			xlate->host_fmt =
1037f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8);
1038f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			xlate->code	= code;
1039f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			dev_dbg(dev, "Providing host format %s for sensor code %d\n",
1040f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			       xlate->host_fmt->name, code);
1041f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			xlate++;
1042f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		}
1043f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	}
1044f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
1045f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	/* Generic pass-trough */
1046f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	formats++;
1047f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (xlate) {
1048f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		xlate->host_fmt = fmt;
1049f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		xlate->code	= code;
1050f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		xlate++;
1051f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	}
1052f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	return formats;
1053f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin}
1054f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
10552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx2_camera_set_fmt(struct soc_camera_device *icd,
10562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			       struct v4l2_format *f)
10572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
1058f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
1059f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct mx2_camera_dev *pcdev = ici->priv;
10602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
10612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	const struct soc_camera_format_xlate *xlate;
10622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_pix_format *pix = &f->fmt.pix;
10632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_mbus_framefmt mf;
10642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int ret;
10652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
10672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!xlate) {
10687dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		dev_warn(icd->parent, "Format %x not found\n",
10692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				pix->pixelformat);
10702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return -EINVAL;
10712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
10722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.width	= pix->width;
10742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.height	= pix->height;
10752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.field	= pix->field;
10762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.colorspace	= pix->colorspace;
10772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.code		= xlate->code;
10782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
10802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (ret < 0 && ret != -ENOIOCTLCMD)
10812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return ret;
10822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mf.code != xlate->code)
10842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return -EINVAL;
10852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->width		= mf.width;
10872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->height		= mf.height;
10882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->field		= mf.field;
10892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->colorspace		= mf.colorspace;
10902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	icd->current_fmt	= xlate;
10912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1092f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (mx27_camera_emma(pcdev))
1093f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
1094f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin						xlate->host_fmt->fourcc);
1095f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin
10962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
10972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
10982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
10992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx2_camera_try_fmt(struct soc_camera_device *icd,
11002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				  struct v4l2_format *f)
11012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
11022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
11032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	const struct soc_camera_format_xlate *xlate;
11042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_pix_format *pix = &f->fmt.pix;
11052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct v4l2_mbus_framefmt mf;
11062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	__u32 pixfmt = pix->pixelformat;
11072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned int width_limit;
11082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int ret;
11092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
11112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pixfmt && !xlate) {
11127dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		dev_warn(icd->parent, "Format %x not found\n", pixfmt);
11132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return -EINVAL;
11142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
11152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* FIXME: implement MX27 limits */
11172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* limit to MX25 hardware capabilities */
11192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (cpu_is_mx25()) {
11202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (xlate->host_fmt->bits_per_sample <= 8)
11212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			width_limit = 0xffff * 4;
11222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		else
11232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			width_limit = 0xffff * 2;
11242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		/* CSIIMAG_PARA limit */
11252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pix->width > width_limit)
11262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pix->width = width_limit;
11272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pix->height > 0xffff)
11282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pix->height = 0xffff;
11292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
11312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				xlate->host_fmt);
11322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (pix->bytesperline < 0)
11332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			return pix->bytesperline;
11342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pix->sizeimage = pix->height * pix->bytesperline;
113528281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski		/* Check against the CSIRXCNT limit */
113628281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski		if (pix->sizeimage > 4 * 0x3ffff) {
113728281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski			/* Adjust geometry, preserve aspect ratio */
113828281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski			unsigned int new_height = int_sqrt(4 * 0x3ffff *
113928281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski					pix->height / pix->bytesperline);
114028281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski			pix->width = new_height * pix->width / pix->height;
114128281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski			pix->height = new_height;
114228281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski			pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
114328281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski							xlate->host_fmt);
114428281a71eb3bc08a0fb9514886e7d6e868f71b3fGuennadi Liakhovetski			BUG_ON(pix->bytesperline < 0);
11452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		}
11462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
11472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* limit to sensor capabilities */
11492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.width	= pix->width;
11502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.height	= pix->height;
11512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.field	= pix->field;
11522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.colorspace	= pix->colorspace;
11532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mf.code		= xlate->code;
11542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
11562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (ret < 0)
11572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return ret;
11582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mf.field == V4L2_FIELD_ANY)
11602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mf.field = V4L2_FIELD_NONE;
1161f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	/*
1162f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * Driver supports interlaced images provided they have
1163f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * both fields so that they can be processed as if they
1164f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 * were progressive.
1165f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	 */
1166f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) {
11677dfff95366f48bf66f77c17cdc9ebd8be696ac5dGuennadi Liakhovetski		dev_err(icd->parent, "Field type %d unsupported.\n",
11682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				mf.field);
11692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return -EINVAL;
11702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
11712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->width	= mf.width;
11732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->height	= mf.height;
11742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->field	= mf.field;
11752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pix->colorspace	= mf.colorspace;
11762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
11782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
11792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int mx2_camera_querycap(struct soc_camera_host *ici,
11812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			       struct v4l2_capability *cap)
11822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
11832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* cap->name is set by the friendly caller:-> */
11842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
11852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
11862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
11882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
11892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11906b101926f98b54549128db4d34f4a73b5f03feccSascha Hauerstatic int mx2_camera_reqbufs(struct soc_camera_device *icd,
11912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			      struct v4l2_requestbuffers *p)
11922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
11932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int i;
11942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
11952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	for (i = 0; i < p->count; i++) {
11966b101926f98b54549128db4d34f4a73b5f03feccSascha Hauer		struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
11972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach						      struct mx2_buffer, vb);
11982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		INIT_LIST_HEAD(&buf->vb.queue);
11992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
12002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
12022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
12032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef CONFIG_MACH_MX27
12052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state)
12062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
12072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct videobuf_buffer *vb;
12082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer *buf;
12092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long flags;
12102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int ret;
12112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_lock_irqsave(&pcdev->lock, flags);
12132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!pcdev->active) {
12152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(pcdev->dev, "%s called with no active buffer!\n",
12162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				__func__);
12172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto out;
12182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
12192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb = &pcdev->active->vb;
12212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	buf = container_of(vb, struct mx2_buffer, vb);
12222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	WARN_ON(list_empty(&vb->queue));
12232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
12242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb, vb->baddr, vb->bsize);
12252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
12272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	list_del_init(&vb->queue);
12282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->state = state;
12292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	do_gettimeofday(&vb->ts);
12302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->field_count++;
12312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	wake_up(&vb->done);
12332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (list_empty(&pcdev->capture)) {
12352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->active = NULL;
12362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto out;
12372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
12382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->active = list_entry(pcdev->capture.next,
12402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			struct mx2_buffer, vb.queue);
12412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb = &pcdev->active->vb;
12432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->state = VIDEOBUF_ACTIVE;
12442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb),
12462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ);
12472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (ret) {
12492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->state = VIDEOBUF_ERROR;
12502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->active = NULL;
12512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		wake_up(&vb->done);
12522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
12532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachout:
12552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_unlock_irqrestore(&pcdev->lock, flags);
12562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
12572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx27_camera_dma_err_callback(int channel, void *data, int err)
12592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
12602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = data;
12612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR);
12632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
12642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx27_camera_dma_callback(int channel, void *data)
12662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
12672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = data;
12682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	mx27_camera_frame_done(pcdev, VIDEOBUF_DONE);
12702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
12712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#define DMA_REQ_CSI_RX          31 /* FIXME: Add this to a resource */
12732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int __devinit mx27_camera_dma_init(struct platform_device *pdev,
12752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		struct mx2_camera_dev *pcdev)
12762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
12772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int err;
12782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH);
12802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->dma < 0) {
12812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(&pdev->dev, "%s failed to request DMA channel\n",
12822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				__func__);
12832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return pcdev->dma;
12842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
12852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback,
12872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach					mx27_camera_dma_err_callback, pcdev);
12882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (err) {
12892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(&pdev->dev, "%s failed to set DMA callback\n",
12902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				__func__);
12912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto err_out;
12922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
12932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
12942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	err = imx_dma_config_channel(pcdev->dma,
12952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
12962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
12972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			DMA_REQ_CSI_RX, 1);
12982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (err) {
12992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(&pdev->dev, "%s failed to config DMA channel\n",
13002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				__func__);
13012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto err_out;
13022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
13032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	imx_dma_config_burstlen(pcdev->dma, 64);
13052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
13072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siacherr_out:
13092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	imx_dma_free(pcdev->dma);
13102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return err;
13122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
13132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif /* CONFIG_MACH_MX27 */
13142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
13162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
13176b101926f98b54549128db4d34f4a73b5f03feccSascha Hauer	struct soc_camera_device *icd = file->private_data;
13182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13196b101926f98b54549128db4d34f4a73b5f03feccSascha Hauer	return videobuf_poll_stream(file, &icd->vb_vidq, pt);
13202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
13212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic struct soc_camera_host_ops mx2_soc_camera_host_ops = {
13232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.owner		= THIS_MODULE,
13242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.add		= mx2_camera_add_device,
13252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.remove		= mx2_camera_remove_device,
13262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.set_fmt	= mx2_camera_set_fmt,
13272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.set_crop	= mx2_camera_set_crop,
1328f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	.get_formats	= mx2_camera_get_formats,
13292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.try_fmt	= mx2_camera_try_fmt,
13302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.init_videobuf	= mx2_camera_init_videobuf,
13312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.reqbufs	= mx2_camera_reqbufs,
13322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.poll		= mx2_camera_poll,
13332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.querycap	= mx2_camera_querycap,
13342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.set_bus_param	= mx2_camera_set_bus_param,
13352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach};
13362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
13382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		int bufnum, int state)
13392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
1340f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
1341f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	struct mx2_fmt_cfg *prp = pcdev->emma_prp;
13422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer *buf;
13432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct videobuf_buffer *vb;
13442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned long phys;
13452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!list_empty(&pcdev->active_bufs)) {
13472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		buf = list_entry(pcdev->active_bufs.next,
13482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			struct mx2_buffer, vb.queue);
13492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		BUG_ON(buf->bufnum != bufnum);
13512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb = &buf->vb;
13532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef DEBUG
13542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		phys = videobuf_to_dma_contig(vb);
1355f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		if (prp->cfg.channel == 1) {
1356f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
1357f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				4 * bufnum) != phys) {
1358f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				dev_err(pcdev->dev, "%p != %p\n", phys,
1359f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin						readl(pcdev->base_emma +
1360f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin							PRP_DEST_RGB1_PTR +
1361f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin							4 * bufnum));
1362f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			}
1363f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		} else {
1364f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			if (readl(pcdev->base_emma + PRP_DEST_Y_PTR -
1365f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				0x14 * bufnum) != phys) {
1366f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				dev_err(pcdev->dev, "%p != %p\n", phys,
1367f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin						readl(pcdev->base_emma +
1368f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin							PRP_DEST_Y_PTR -
1369f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin							0x14 * bufnum));
1370f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			}
13712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		}
13722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif
13732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
13742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				vb->baddr, vb->bsize);
13752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		list_del(&vb->queue);
13772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		vb->state = state;
13782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		do_gettimeofday(&vb->ts);
1379ccd1a499c1675fef5d2a138617507add63cb81dbJavier Martin		vb->field_count = pcdev->frame_count * 2;
1380ccd1a499c1675fef5d2a138617507add63cb81dbJavier Martin		pcdev->frame_count++;
13812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		wake_up(&vb->done);
13832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
13842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
13852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (list_empty(&pcdev->capture)) {
1386f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		if (prp->cfg.channel == 1) {
1387f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(pcdev->discard_buffer_dma, pcdev->base_emma +
1388f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin					PRP_DEST_RGB1_PTR + 4 * bufnum);
1389f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		} else {
1390f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(pcdev->discard_buffer_dma, pcdev->base_emma +
1391f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin						PRP_DEST_Y_PTR -
1392f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin						0x14 * bufnum);
1393f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
1394f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				writel(pcdev->discard_buffer_dma + imgsize,
1395f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				       pcdev->base_emma + PRP_DEST_CB_PTR -
1396f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				       0x14 * bufnum);
1397f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				writel(pcdev->discard_buffer_dma +
1398f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				       ((5 * imgsize) / 4), pcdev->base_emma +
1399f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				       PRP_DEST_CR_PTR - 0x14 * bufnum);
1400f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			}
1401f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		}
14022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		return;
14032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
14042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	buf = list_entry(pcdev->capture.next,
14062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			struct mx2_buffer, vb.queue);
14072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
1408cd9ebdbc0541b4e8ee145c81642d68332f79b932Michael Grzeschik	buf->bufnum = !bufnum;
14092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
14112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb = &buf->vb;
14132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	vb->state = VIDEOBUF_ACTIVE;
14142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	phys = videobuf_to_dma_contig(vb);
1416f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if (prp->cfg.channel == 1) {
1417f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
1418f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	} else {
1419f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(phys, pcdev->base_emma +
1420f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin				PRP_DEST_Y_PTR - 0x14 * bufnum);
1421f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
1422f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(phys + imgsize, pcdev->base_emma +
1423f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin					PRP_DEST_CB_PTR - 0x14 * bufnum);
1424f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin			writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
1425f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin					PRP_DEST_CR_PTR - 0x14 * bufnum);
1426f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		}
1427f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	}
14282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
14292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
14312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
14322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = data;
14332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
14342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_buffer *buf;
14352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (status & (1 << 7)) { /* overflow */
14372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		u32 cntl;
14382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		/*
14392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * We only disable channel 1 here since this is the only
14402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * enabled channel
14412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 *
14422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * FIXME: the correct DMA overflow handling should be resetting
14432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * the buffer, returning an error frame, and continuing with
14442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * the next one.
14452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 */
14462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		cntl = readl(pcdev->base_emma + PRP_CNTL);
1447f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN),
1448f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		       pcdev->base_emma + PRP_CNTL);
14492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		writel(cntl, pcdev->base_emma + PRP_CNTL);
14502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
1451f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if ((((status & (3 << 5)) == (3 << 5)) ||
1452f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin		((status & (3 << 3)) == (3 << 3)))
14532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			&& !list_empty(&pcdev->active_bufs)) {
14542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		/*
14552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * Both buffers have triggered, process the one we're expecting
14562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 * to first
14572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		 */
14582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		buf = list_entry(pcdev->active_bufs.next,
14592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			struct mx2_buffer, vb.queue);
14602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
14612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
14622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
1463f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if ((status & (1 << 6)) || (status & (1 << 4)))
14642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
1465f410991dcf1fc3ad1d3311b79b4f1b917224ebedJavier Martin	if ((status & (1 << 5)) || (status & (1 << 3)))
14662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
14672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	writel(status, pcdev->base_emma + PRP_INTRSTATUS);
14692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return IRQ_HANDLED;
14712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
14722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev)
14742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
14752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct resource *res_emma = pcdev->res_emma;
14762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int err = 0;
14772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!request_mem_region(res_emma->start, resource_size(res_emma),
14792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				MX2_CAM_DRV_NAME)) {
14802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = -EBUSY;
14812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto out;
14822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
14832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma));
14852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!pcdev->base_emma) {
14862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = -ENOMEM;
14872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_release;
14882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
14892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0,
14912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			MX2_CAM_DRV_NAME, pcdev);
14922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (err) {
14932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
14942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_iounmap;
14952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
14962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
14972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->clk_emma = clk_get(NULL, "emma");
14982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (IS_ERR(pcdev->clk_emma)) {
14992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = PTR_ERR(pcdev->clk_emma);
15002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_free_irq;
15012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
15022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	clk_enable(pcdev->clk_emma);
15042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	err = mx27_camera_emma_prp_reset(pcdev);
15062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (err)
15072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_clk_emma_put;
15082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return err;
15102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_clk_emma_put:
15122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	clk_disable(pcdev->clk_emma);
15132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	clk_put(pcdev->clk_emma);
15142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_free_irq:
15152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	free_irq(pcdev->irq_emma, pcdev);
15162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_iounmap:
15172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	iounmap(pcdev->base_emma);
15182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_release:
15192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	release_mem_region(res_emma->start, resource_size(res_emma));
15202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachout:
15212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return err;
15222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
15232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int __devinit mx2_camera_probe(struct platform_device *pdev)
15252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
15262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev;
15272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct resource *res_csi, *res_emma;
15282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	void __iomem *base_csi;
15292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int irq_csi, irq_emma;
15302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq
15312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		: mx27_camera_irq;
15322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	int err = 0;
15332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	dev_dbg(&pdev->dev, "initialising\n");
15352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0);
15372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	irq_csi = platform_get_irq(pdev, 0);
15382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (res_csi == NULL || irq_csi < 0) {
15392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(&pdev->dev, "Missing platform resources data\n");
15402066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = -ENODEV;
15412066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit;
15422066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
15432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
15452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!pcdev) {
15462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(&pdev->dev, "Could not allocate pcdev\n");
15472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = -ENOMEM;
15482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit;
15492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
15502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->clk_csi = clk_get(&pdev->dev, NULL);
15522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (IS_ERR(pcdev->clk_csi)) {
15532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = PTR_ERR(pcdev->clk_csi);
15542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_kfree;
15552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
15562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n",
15582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			clk_get_rate(pcdev->clk_csi));
15592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/* Initialize DMA */
15612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef CONFIG_MACH_MX27
15622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (cpu_is_mx27()) {
15632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = mx27_camera_dma_init(pdev, pcdev);
15642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (err)
15652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			goto exit_clk_put;
15662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
15672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif /* CONFIG_MACH_MX27 */
15682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->res_csi = res_csi;
15702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->pdata = pdev->dev.platform_data;
15712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (pcdev->pdata) {
15722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		long rate;
15732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		pcdev->platform_flags = pcdev->pdata->flags;
15752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
15772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (rate <= 0) {
15782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			err = -ENODEV;
15792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			goto exit_dma_free;
15802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		}
15812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = clk_set_rate(pcdev->clk_csi, rate);
15822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (err < 0)
15832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			goto exit_dma_free;
15842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
15852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	INIT_LIST_HEAD(&pcdev->capture);
15872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	INIT_LIST_HEAD(&pcdev->active_bufs);
15882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	spin_lock_init(&pcdev->lock);
15892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	/*
15912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 * Request the regions.
15922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	 */
15932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!request_mem_region(res_csi->start, resource_size(res_csi),
15942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				MX2_CAM_DRV_NAME)) {
15952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = -EBUSY;
15962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_dma_free;
15972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
15982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
15992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	base_csi = ioremap(res_csi->start, resource_size(res_csi));
16002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (!base_csi) {
16012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		err = -ENOMEM;
16022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_release;
16032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
16042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->irq_csi = irq_csi;
16052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->base_csi = base_csi;
16062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->base_dma = res_csi->start;
16072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->dev = &pdev->dev;
16082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0,
16102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			MX2_CAM_DRV_NAME, pcdev);
16112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (err) {
16122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		dev_err(pcdev->dev, "Camera interrupt register failed \n");
16132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_iounmap;
16142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
16152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (cpu_is_mx27()) {
16172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		/* EMMA support */
16182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
16192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		irq_emma = platform_get_irq(pdev, 1);
16202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		if (res_emma && irq_emma >= 0) {
16222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			dev_info(&pdev->dev, "Using EMMA\n");
16232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->use_emma = 1;
16242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->res_emma = res_emma;
16252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			pcdev->irq_emma = irq_emma;
16262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			if (mx27_camera_emma_init(pcdev))
16272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach				goto exit_free_irq;
16282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		}
16292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
16302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16312066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->soc_host.drv_name	= MX2_CAM_DRV_NAME,
16322066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->soc_host.ops		= &mx2_soc_camera_host_ops,
16332066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->soc_host.priv		= pcdev;
16342066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->soc_host.v4l2_dev.dev	= &pdev->dev;
16352066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	pcdev->soc_host.nr		= pdev->id;
16362066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	err = soc_camera_host_register(&pcdev->soc_host);
16372066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (err)
16382066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		goto exit_free_emma;
16392066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
164045f4d4e8799ff1d7ef72747203935f1f2533743dMichael Grzeschik	dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n",
164145f4d4e8799ff1d7ef72747203935f1f2533743dMichael Grzeschik			clk_get_rate(pcdev->clk_csi));
164245f4d4e8799ff1d7ef72747203935f1f2533743dMichael Grzeschik
16432066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
16442066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16452066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_free_emma:
16462066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mx27_camera_emma(pcdev)) {
16472066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		free_irq(pcdev->irq_emma, pcdev);
16482066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		clk_disable(pcdev->clk_emma);
16492066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		clk_put(pcdev->clk_emma);
16502066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		iounmap(pcdev->base_emma);
16512066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		release_mem_region(res_emma->start, resource_size(res_emma));
16522066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
16532066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_free_irq:
16542066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	free_irq(pcdev->irq_csi, pcdev);
16552066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_iounmap:
16562066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	iounmap(base_csi);
16572066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_release:
16582066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	release_mem_region(res_csi->start, resource_size(res_csi));
16592066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_dma_free:
16602066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef CONFIG_MACH_MX27
16612066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (cpu_is_mx27())
16622066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		imx_dma_free(pcdev->dma);
16632066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_clk_put:
16642066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	clk_put(pcdev->clk_csi);
16652066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif /* CONFIG_MACH_MX27 */
16662066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit_kfree:
16672066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	kfree(pcdev);
16682066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachexit:
16692066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return err;
16702066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
16712066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16722066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int __devexit mx2_camera_remove(struct platform_device *pdev)
16732066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
16742066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
16752066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct mx2_camera_dev *pcdev = container_of(soc_host,
16762066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach			struct mx2_camera_dev, soc_host);
16772066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	struct resource *res;
16782066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16792066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	clk_put(pcdev->clk_csi);
16802066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#ifdef CONFIG_MACH_MX27
16812066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (cpu_is_mx27())
16822066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		imx_dma_free(pcdev->dma);
16832066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach#endif /* CONFIG_MACH_MX27 */
16842066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	free_irq(pcdev->irq_csi, pcdev);
16852066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mx27_camera_emma(pcdev))
16862066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		free_irq(pcdev->irq_emma, pcdev);
16872066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16882066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	soc_camera_host_unregister(&pcdev->soc_host);
16892066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16902066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	iounmap(pcdev->base_csi);
16912066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
16922066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	if (mx27_camera_emma(pcdev)) {
16932066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		clk_disable(pcdev->clk_emma);
16942066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		clk_put(pcdev->clk_emma);
16952066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		iounmap(pcdev->base_emma);
16962066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		res = pcdev->res_emma;
16972066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		release_mem_region(res->start, resource_size(res));
16982066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	}
16992066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17002066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	res = pcdev->res_csi;
17012066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	release_mem_region(res->start, resource_size(res));
17022066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17032066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	kfree(pcdev);
17042066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17052066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	dev_info(&pdev->dev, "MX2 Camera driver unloaded\n");
17062066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17072066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return 0;
17082066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
17092066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17102066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic struct platform_driver mx2_camera_driver = {
17112066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.driver 	= {
17122066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach		.name	= MX2_CAM_DRV_NAME,
17132066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	},
17142066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	.remove		= __devexit_p(mx2_camera_remove),
17152066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach};
17162066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17172066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17182066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic int __init mx2_camera_init(void)
17192066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
17202066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe);
17212066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
17222066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17232066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachstatic void __exit mx2_camera_exit(void)
17242066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach{
17252066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach	return platform_driver_unregister(&mx2_camera_driver);
17262066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach}
17272066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17282066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachmodule_init(mx2_camera_init);
17292066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siachmodule_exit(mx2_camera_exit);
17302066930de6296ef7470de11eaa9b8bc9129721e8Baruch Siach
17312066930de6296ef7470de11eaa9b8bc9129721e8Baruch SiachMODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
17322066930de6296ef7470de11eaa9b8bc9129721e8Baruch SiachMODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
17332066930de6296ef7470de11eaa9b8bc9129721e8Baruch SiachMODULE_LICENSE("GPL");
173464dc3c1a906467d90c24913b0b38dd13d9378f4fMauro Carvalho ChehabMODULE_VERSION(MX2_CAM_VERSION);
1735