Subject: fix camera handling in mx27 BSP + fix second serial line
From: Marc Kleine-Budde <mkl@pengutronix.de>

This patches should fix the camera handling in the
OSELAS.BSP-Phytec-phyCORE-i.MX27-6
BSP release.

Additionally this patch fixes the various problems on the serial line
- div by zero when opening /dev/ttymxc{1,2}
- RX on second line
- interrupt floods on RTS low

With this patch the version of the BSP is also bumped to 6.3

---

Note: This patch can only be used on top a clean

   OSELAS.BSP-Phytec-phyCORE-i.MX27-6
   ----------------------------------

This BSP can be found at http://www.pengutronix.de/oselas/bsp/phytec/

Steps to use this patch:

 $ tar xf OSELAS.BSP-Phytec-phyCORE-i.MX27-6.tar.gz
 $ cd OSELAS.BSP-Phytec-phyCORE-i.MX27-6
 $ patch -p0 < this-patch-file

After these steps you can build the whole BSP as the quickstart mentioned.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

---
 ChangeLog                                                                                  |   28 
 patches/linux-2.6.25/generic/0001--ARM-serial-imx-set-RXD-mux-bit-on-i.MX27-and-i.MX.patch |   48 
 patches/linux-2.6.25/generic/0002--ARM-serial-imx-fix-rts-handling-for-non-imx1-base.patch |   31 
 patches/linux-2.6.25/generic/0003--ARM-pcm038-fix-uart2-pin-definitions.patch              |   33 
 patches/linux-2.6.25/generic/01_mxc_irq_priority.diff                                      |  149 +
 patches/linux-2.6.25/generic/02_mx2_camera_driver_fixes.diff                               |  222 ++
 patches/linux-2.6.25/generic/03_drivers_media_video_soc_camera_multiple_cameras.diff       |  172 ++
 patches/linux-2.6.25/generic/04_drivers_media_video_mt9m001_fix_gpio.diff                  |  121 +
 patches/linux-2.6.25/generic/05_drivers_media_video_mt9v022_fix_gpio.diff                  |  112 +
 patches/linux-2.6.25/generic/06_phytec_pcm970_baseboard_camera_fixes.diff                  |   20 
 patches/linux-2.6.25/generic/serial-imx-25-26.diff                                         |  749 ++++++++++
 patches/linux-2.6.25/generic/series                                                        |   14 
 ptxconfig                                                                                  |    2 
 13 files changed, 1700 insertions(+), 1 deletion(-)

Index: ChangeLog
===================================================================
--- ChangeLog.orig
+++ ChangeLog
@@ -1,3 +1,31 @@
+2008-07-30	Marc Kleine-Budde <mkl@pengutronix.de>
+
+		* BSP: Release 6.3
+
+2008-07-30	Marc Kleine-Budde <mkl@pengutronix.de>
+
+		* kernel: i.MX27 serial
+		added forgotten patch (backport of 2.6.26 serial driver)
+
+2008-07-28	Marc Kleine-Budde <mkl@pengutronix.de>
+
+		* BSP: Release 6.2
+
+2008-07-28	Marc Kleine-Budde <mkl@pengutronix.de>
+
+		* kernel: i.MX27 serial
+		fixed second serial channel
+		fixed IRQ flood on RTS low
+
+2008-07-25      Marc Kleine-Budde <mkl@pengutronix.de>
+
+		* BSP: Release 6.1
+
+2008-07-25	Marc Kleine-Budde <mkl@pengutronix.de>
+
+		* kernel: i.MX27 camera
+		- add current patches from sha
+
 2008-08-03	Juergen Beisert <j.beisert@pengutronix.de>
 
 		* kernel: i.MX27 audio driver
Index: patches/linux-2.6.25/generic/0001--ARM-serial-imx-set-RXD-mux-bit-on-i.MX27-and-i.MX.patch
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/0001--ARM-serial-imx-set-RXD-mux-bit-on-i.MX27-and-i.MX.patch
@@ -0,0 +1,48 @@
+From b4897199e24db27f758029aa043cc3648cab2d01 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Mon, 28 Jul 2008 12:10:34 +0200
+Subject: [PATCH] [ARM] serial imx: set RXD mux bit on i.MX27 and i.MX31
+
+RX in i.MX27 and i.MX31 UART lines does not work unless the
+"RXD  Muxed Input Select" bit is set on i.MX27 and i.MX31 processors.
+
+This patch sets the missing RXD mux bit in the UCR3 register.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/serial/imx.c |   15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+Index: drivers/serial/imx.c
+===================================================================
+--- drivers/serial/imx.c.orig
++++ drivers/serial/imx.c
+@@ -127,8 +127,13 @@
+ #define  UCR3_RXDSEN	 (1<<6)  /* Receive status interrupt enable */
+ #define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
+ #define  UCR3_AWAKEN	 (1<<4)  /* Async wake interrupt enable */
+-#define  UCR3_REF25 	 (1<<3)  /* Ref freq 25 MHz */
+-#define  UCR3_REF30 	 (1<<2)  /* Ref Freq 30 MHz */
++#ifdef CONFIG_ARCH_IMX
++#define  UCR3_REF25 	 (1<<3)  /* Ref freq 25 MHz, only on mx1 */
++#define  UCR3_REF30 	 (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
++#endif
++#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
++#define  UCR3_RXDMUXSEL	 (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
++#endif
+ #define  UCR3_INVT  	 (1<<1)  /* Inverted Infrared transmission */
+ #define  UCR3_BPEN  	 (1<<0)  /* Preset registers enable */
+ #define  UCR4_CTSTL_32   (32<<10) /* CTS trigger level (32 chars) */
+@@ -598,6 +603,12 @@ static int imx_startup(struct uart_port 
+ 	temp |= (UCR2_RXEN | UCR2_TXEN);
+ 	writel(temp, sport->port.membase + UCR2);
+ 
++#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
++	temp = readl(sport->port.membase + UCR3);
++	temp |= UCR3_RXDMUXSEL;
++	writel(temp, sport->port.membase + UCR3);
++#endif
++
+ 	/*
+ 	 * Enable modem status interrupts
+ 	 */
Index: patches/linux-2.6.25/generic/0002--ARM-serial-imx-fix-rts-handling-for-non-imx1-base.patch
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/0002--ARM-serial-imx-fix-rts-handling-for-non-imx1-base.patch
@@ -0,0 +1,31 @@
+From 59424e2ba54eea20b78db31846866d7f08985bae Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Mon, 28 Jul 2008 21:26:01 +0200
+Subject: [PATCH] [ARM] serial imx: fix rts handling for non imx1 based hardware
+
+The interrupt handler for muxed interrupts (imx2/imx3) was calling
+the rts handling subroutine if the RTSS bit was set.
+(Which indicates the status of the RTS line), leading to an
+interrupt flood on RTS bit low.
+
+This patch fixes the problem by looking at the RTSD bit instead,
+indicating a change in the RTS line.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/serial/imx.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: drivers/serial/imx.c
+===================================================================
+--- drivers/serial/imx.c.orig
++++ drivers/serial/imx.c
+@@ -450,7 +450,7 @@ static irqreturn_t imx_int(int irq, void
+ 			readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
+ 		imx_txint(irq, dev_id);
+ 
+-	if (sts & USR1_RTSS)
++	if (sts & USR1_RTSD)
+ 		imx_rtsint(irq, dev_id);
+ 
+ 	return IRQ_HANDLED;
Index: patches/linux-2.6.25/generic/0003--ARM-pcm038-fix-uart2-pin-definitions.patch
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/0003--ARM-pcm038-fix-uart2-pin-definitions.patch
@@ -0,0 +1,33 @@
+From 6c4efcefee0b55c5701c4431b2c87dceeaa4a90d Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Mon, 28 Jul 2008 12:35:49 +0200
+Subject: [PATCH] [ARM] pcm038: fix uart2 pin definitions
+
+This patch fixes the pin definitions of the uart2.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ arch/arm/mach-mx2/pcm038.c |   10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+Index: arch/arm/mach-mx2/pcm038.c
+===================================================================
+--- arch/arm/mach-mx2/pcm038.c.orig
++++ arch/arm/mach-mx2/pcm038.c
+@@ -223,10 +223,12 @@ static int uart_mxc_port1_exit(struct pl
+ 			MXC_GPIO_ALLOC_MODE_RELEASE, "UART1");
+ }
+ 
+-static int mxc_uart2_pins[] = { PE10_PF_UART3_CTS,
+-				PE9_PF_UART3_RXD,
+-				PE10_PF_UART3_CTS,
+-				PE9_PF_UART3_RXD };
++static int mxc_uart2_pins[] = {
++	PE8_PF_UART3_TXD,
++	PE9_PF_UART3_RXD,
++	PE10_PF_UART3_CTS,
++	PE11_PF_UART3_RTS
++};
+ 
+ static int uart_mxc_port2_init(struct platform_device *pdev)
+ {
Index: patches/linux-2.6.25/generic/01_mxc_irq_priority.diff
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/01_mxc_irq_priority.diff
@@ -0,0 +1,149 @@
+---
+ arch/arm/plat-mxc/dma_mx2.c            |    4 ++++
+ arch/arm/plat-mxc/irq.c                |   21 +++++++++++++++++++--
+ include/asm-arm/arch-mxc/common.h      |    2 +-
+ include/asm-arm/arch-mxc/entry-macro.S |   14 ++++++++++++--
+ include/asm-arm/arch-mxc/mxc.h         |   10 ++--------
+ 5 files changed, 38 insertions(+), 13 deletions(-)
+
+Index: arch/arm/plat-mxc/irq.c
+===================================================================
+--- arch/arm/plat-mxc/irq.c.orig
++++ arch/arm/plat-mxc/irq.c
+@@ -44,6 +44,23 @@ static struct irq_chip mxc_avic_chip = {
+ 	.unmask = mxc_unmask_irq,
+ };
+ 
++void mxc_irq_set_priority(unsigned int irq, unsigned char prio)
++{
++	unsigned int temp;
++	int shift = (irq % 8) * 4;
++
++	if (irq > 63)
++		return;
++printk("%s: %d %p\n", __func__, irq, AVIC_NIPRIORITY(irq));
++	temp = __raw_readl(AVIC_NIPRIORITY(irq));
++printk("temp: 0x%08x\n", temp);
++	temp &= ~(0xF << shift);
++	temp |= (prio & 0xF) << shift;
++printk("temp: 0x%08x\n", temp);
++	__raw_writel(temp, AVIC_NIPRIORITY(irq));
++}
++EXPORT_SYMBOL(mxc_irq_set_priority);
++
+ /*
+  * This function initializes the AVIC hardware and disables all the
+  * interrupts. It registers the interrupt enable and disable functions
+@@ -72,11 +89,11 @@ void __init mxc_init_irq(void)
+ 		set_irq_handler(i, handle_level_irq);
+ 		set_irq_flags(i, IRQF_VALID);
+ 	}
+-
++#if 0
+ 	/* Set WDOG2's interrupt the highest priority level (bit 28-31) */
+ 	reg = __raw_readl(AVIC_NIPRIORITY6);
+ 	reg |= (0xF << 28);
+ 	__raw_writel(reg, AVIC_NIPRIORITY6);
+-
++#endif
+ 	printk(KERN_INFO "MXC IRQ initialized\n");
+ }
+Index: include/asm-arm/arch-mxc/common.h
+===================================================================
+--- include/asm-arm/arch-mxc/common.h.orig
++++ include/asm-arm/arch-mxc/common.h
+@@ -18,5 +18,5 @@ extern void mxc_init_irq(void);
+ extern struct sys_timer mxc_timer;
+ extern void mxc_timer_init(void);
+ extern int mxc_clocks_init(void);
+-
++extern void mxc_irq_set_priority(unsigned int, unsigned char);
+ #endif
+Index: include/asm-arm/arch-mxc/entry-macro.S
+===================================================================
+--- include/asm-arm/arch-mxc/entry-macro.S.orig
++++ include/asm-arm/arch-mxc/entry-macro.S
+@@ -8,12 +8,16 @@
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  */
++#define AVIC_NIVECSR	0x40
++#define AVIC_NIMASK	0x04
+ 
+ 	@ this macro disables fast irq (not implemented)
+ 	.macro	disable_fiq
+ 	.endm
+ 
+ 	.macro  get_irqnr_preamble, base, tmp
++	ldr	\base, =AVIC_IO_ADDRESS(AVIC_BASE_ADDR)
++	ldr	r4, [\base, #AVIC_NIMASK]
+ 	.endm
+ 
+ 	.macro  arch_ret_to_user, tmp1, tmp2
+@@ -23,15 +27,21 @@
+ 	@ and returns its number in irqnr
+ 	@ and returns if an interrupt occured in irqstat
+ 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+-	ldr	\base, =AVIC_IO_ADDRESS(AVIC_BASE_ADDR)
++
+ 	@ Load offset & priority of the highest priority
+ 	@ interrupt pending from AVIC_NIVECSR
+-	ldr	\irqstat, [\base, #0x40]
++	ldr	\irqstat, [\base, #AVIC_NIVECSR]
++
+ 	@ Shift to get the decoded IRQ number, using ASR so
+ 	@ 'no interrupt pending' becomes 0xffffffff
+ 	mov	\irqnr, \irqstat, asr #16
++
+ 	@ set zero flag if IRQ + 1 == 0
+ 	adds	\tmp, \irqnr, #1
++	bicne	\tmp, \irqstat, #0xFFFFFFE0
++	strne	\tmp, [\base, #AVIC_NIMASK]
++	streq	r4, [\base, #AVIC_NIMASK]
++
+ 	.endm
+ 
+ 	@ irq priority table (not used)
+Index: include/asm-arm/arch-mxc/mxc.h
+===================================================================
+--- include/asm-arm/arch-mxc/mxc.h.orig
++++ include/asm-arm/arch-mxc/mxc.h
+@@ -40,14 +40,8 @@
+ #define AVIC_INTENABLEL		(AVIC_BASE + 0x14)	/* int enable reg low */
+ #define AVIC_INTTYPEH		(AVIC_BASE + 0x18)	/* int type reg high */
+ #define AVIC_INTTYPEL		(AVIC_BASE + 0x1C)	/* int type reg low */
+-#define AVIC_NIPRIORITY7	(AVIC_BASE + 0x20)	/* norm int priority lvl7 */
+-#define AVIC_NIPRIORITY6	(AVIC_BASE + 0x24)	/* norm int priority lvl6 */
+-#define AVIC_NIPRIORITY5	(AVIC_BASE + 0x28)	/* norm int priority lvl5 */
+-#define AVIC_NIPRIORITY4	(AVIC_BASE + 0x2C)	/* norm int priority lvl4 */
+-#define AVIC_NIPRIORITY3	(AVIC_BASE + 0x30)	/* norm int priority lvl3 */
+-#define AVIC_NIPRIORITY2	(AVIC_BASE + 0x34)	/* norm int priority lvl2 */
+-#define AVIC_NIPRIORITY1	(AVIC_BASE + 0x38)	/* norm int priority lvl1 */
+-#define AVIC_NIPRIORITY0	(AVIC_BASE + 0x3C)	/* norm int priority lvl0 */
++#define AVIC_NIPRIORITY(irq)	(AVIC_BASE + 0x3C - ((irq) >> 3) * 4)
++							/* int priority register based on irq number */
+ #define AVIC_NIVECSR		(AVIC_BASE + 0x40)	/* norm int vector/status */
+ #define AVIC_FIVECSR		(AVIC_BASE + 0x44)	/* fast int vector/status */
+ #define AVIC_INTSRCH		(AVIC_BASE + 0x48)	/* int source reg high */
+Index: arch/arm/plat-mxc/dma_mx2.c
+===================================================================
+--- arch/arm/plat-mxc/dma_mx2.c.orig
++++ arch/arm/plat-mxc/dma_mx2.c
+@@ -36,6 +36,7 @@
+ #include <asm/dma.h>
+ #include <asm/io.h>
+ #include <asm/arch/imx-dma.h>
++#include <asm/arch/common.h>
+ 
+ struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
+ 
+@@ -579,6 +580,9 @@ int imx_dma_request(imx_dmach_t dma_ch, 
+ 		printk(KERN_CRIT "Can't register IRQ %d for DMA channel %d\n", INT_DMACH0 + dma_ch, dma_ch);
+ 		return ret;
+ 	}
++
++	mxc_irq_set_priority(INT_DMACH0 + dma_ch, dma_ch);
++
+ 	init_timer(&imxdma->watchdog);
+ 	imxdma->watchdog.function = &imx_dma_watchdog;
+ 	imxdma->watchdog.data = dma_ch;
Index: patches/linux-2.6.25/generic/02_mx2_camera_driver_fixes.diff
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/02_mx2_camera_driver_fixes.diff
@@ -0,0 +1,222 @@
+---
+ drivers/media/video/mx27_camera.c |   82 +++++++++++++++++++++++++-------------
+ 1 file changed, 56 insertions(+), 26 deletions(-)
+
+Index: drivers/media/video/mx27_camera.c
+===================================================================
+--- drivers/media/video/mx27_camera.c.orig
++++ drivers/media/video/mx27_camera.c
+@@ -38,6 +38,7 @@
+ #include <asm/arch/pmic/power.h>
+ #include <asm/arch/imx-dma.h>
+ #include <asm/arch/dma.h>
++#include <asm/arch/common.h>
+ 
+ #include <asm/dma.h>
+ 
+@@ -114,11 +115,6 @@ static const char *mx27_cam_driver_descr
+ #define CSIRXCNT	0x14
+ #define CSICR3		0x1C
+ 
+-/* Currently we do not need irqs. All we need is DMA callback
+- * Leave it here for reference for some time.
+- */
+-#undef MX27_CAMERA_USE_IRQ
+-
+ struct mx27_camera_dev {
+ 	struct device		*dev;
+ 	struct soc_camera_device *icd;
+@@ -218,15 +214,19 @@ static void mx27_camera_activate(struct 
+ 
+ 	csicr1 |= CSICR1_MCLKDIV(mclk_get_divisor(pcdev));
+ 
+-	csicr1 |= CSICR1_MCLKEN | CSICR1_RXFF_LEVEL(2);
++	csicr1 |= CSICR1_MCLKEN | CSICR1_RXFF_LEVEL(2) | CSICR1_SOF_INTEN;
++
++	pcdev->active = NULL;
+ 
+ 	clk_enable(pcdev->clk);
+ 	writel(csicr1, pcdev->base + CSICR1);
+ }
+ 
++
+ static void mx27_camera_deactivate(struct mx27_camera_dev *pcdev)
+ {
+ 	clk_disable(pcdev->clk);
++	pcdev->active = NULL;
+ 	writel(0, pcdev->base + CSICR1);
+ }
+ 
+@@ -277,16 +277,45 @@ static void mx27_camera_remove_device(st
+ 	pcdev->icd = NULL;
+ }
+ 
+-#ifdef MX27_CAMERA_USE_IRQ
++static void mx27_camera_dma_enable(struct mx27_camera_dev *pcdev)
++{
++	u32 tmp;
++
++	imx_dma_enable(pcdev->dma);
++
++	tmp = readl(pcdev->base + CSICR1);
++	tmp |= CSICR1_RF_OR_INTEN;
++	writel(tmp, pcdev->base + CSICR1);
++}
++
++static int ovl = 0;
++
+ static irqreturn_t mx27_camera_irq(int irq, void *data)
+ {
+ 	struct mx27_camera_dev *pcdev = data;
+ 	u32 status = readl(pcdev->base + CSISR);
+-	unsigned long flags;
++
++	if (status & CSISR_SOF_INT && pcdev->active) {
++		u32 tmp;
++
++		tmp = readl(pcdev->base + CSICR1);
++		tmp |= CSICR1_CLR_RXFIFO;
++		writel(tmp, pcdev->base + CSICR1);
++		mx27_camera_dma_enable(pcdev);
++		writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base + CSISR);
++		status &= ~CSISR_RFF_OR_INT;
++	}
++
++	if (status & CSISR_SOF_INT && !pcdev->active)
++		ovl = 0;
++
++	if (status & CSISR_RFF_OR_INT)
++		ovl++;
++
++	writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base + CSISR);
+ 
+ 	return IRQ_HANDLED;
+ }
+-#endif
+ 
+ static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+ 
+@@ -392,7 +421,6 @@ static void mx27_videobuf_queue(struct v
+ 	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ 	unsigned long flags;
+ 	int ret;
+-	u32 tmp;
+ 
+ 	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ 		vb, vb->baddr, vb->bsize);
+@@ -414,16 +442,10 @@ static void mx27_videobuf_queue(struct v
+ 			wake_up(&vb->done);
+ 			goto out;
+ 		}
++
+ 		pcdev->active = buf;
+-		writel(CSISR_SOF_INT, pcdev->base + CSISR);
+-		while(!(readl(pcdev->base + CSISR) & CSISR_SOF_INT));
+-		tmp = readl(pcdev->base + CSICR1) | CSICR1_CLR_RXFIFO;
+-		writel(tmp, pcdev->base + CSICR1);
+-		imx_dma_enable(pcdev->dma);
+ 	}
+ 
+-	writel(0x100, pcdev->base + CSIRXCNT);
+-
+ 	dev_dbg(&icd->dev, "nents=%d sg=0x%p\n",
+ 		dma->sglen, dma->sglist);
+ out:
+@@ -507,6 +529,7 @@ static void mx27_camera_frame_done(struc
+ 	struct mx27_buffer *buf;
+ 	struct videobuf_dmabuf *dma;
+ 	int ret;
++	u32 tmp;
+ 
+ 	if (!pcdev->active) {
+ 		dev_err(pcdev->dev, "DMA End IRQ with no active buffer!\n");
+@@ -525,6 +548,15 @@ static void mx27_camera_frame_done(struc
+ 	do_gettimeofday(&vb->ts);
+ 	vb->field_count++;
+ 
++	tmp = readl(pcdev->base + CSICR1);
++	tmp &= ~CSICR1_RF_OR_INTEN;
++	writel(tmp, pcdev->base + CSICR1);
++
++	if (ovl) {
++//		printk("ovl: %d\n", ovl);
++		ovl = 0;
++	}
++
+ 	wake_up(&vb->done);
+ 
+ 	if (list_empty(&pcdev->capture)) {
+@@ -549,7 +581,7 @@ static void mx27_camera_frame_done(struc
+ 		return;
+ 	}
+ 
+-	imx_dma_enable(pcdev->dma);
++	return;
+ }
+ 
+ static void mx27_camera_dma_err_callback(int channel, void *data, int err)
+@@ -663,7 +695,7 @@ static int mx27_camera_probe(struct plat
+ 			IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+ 			DMA_REQ_CSI_RX, 1);
+ 
+-	imx_dma_config_burstlen(pcdev->dma, 64);
++	imx_dma_config_burstlen(pcdev->dma, 0);
+ 
+ 	dev_set_drvdata(&pdev->dev, pcdev);
+ 	pcdev->res = res;
+@@ -671,6 +703,8 @@ static int mx27_camera_probe(struct plat
+ 	pcdev->pdata = pdev->dev.platform_data;
+ 	pcdev->platform_flags = pcdev->pdata->flags;
+ 
++	clk_set_rate(pcdev->clk, pcdev->pdata->clk * 2);
++
+ 	INIT_LIST_HEAD(&pcdev->capture);
+ 	spin_lock_init(&pcdev->lock);
+ 
+@@ -694,14 +728,14 @@ static int mx27_camera_probe(struct plat
+ 
+ 	pcdev->pdata->init(pdev);
+ 
+-#ifdef MX27_CAMERA_USE_IRQ
+ 	err = request_irq(pcdev->irq, mx27_camera_irq, 0, MX27_CAM_DRV_NAME,
+ 			  pcdev);
+ 	if (err) {
+ 		dev_err(pcdev->dev, "Camera interrupt register failed \n");
+ 		goto exit_iounmap;
+ 	}
+-#endif
++
++	mxc_irq_set_priority(pcdev->irq, 14);
+ 
+ 	mx27_soc_camera_host.priv	= pcdev;
+ 	mx27_soc_camera_host.dev.parent	= &pdev->dev;
+@@ -713,10 +747,8 @@ static int mx27_camera_probe(struct plat
+ 	return 0;
+ 
+ exit_free_irq:
+-#ifdef MX27_CAMERA_USE_IRQ
+ 	free_irq(pcdev->irq, pcdev);
+ exit_iounmap:
+-#endif
+ 	iounmap(base);
+ exit_release:
+ 	release_mem_region(res->start, res->end - res->start + 1);
+@@ -738,9 +770,8 @@ static int __devexit mx27_camera_remove(
+ 	clk_put(pcdev->clk);
+ 
+ 	imx_dma_free(pcdev->dma);
+-#ifdef MX27_CAMERA_USE_IRQ
+ 	free_irq(pcdev->irq, pcdev);
+-#endif
++
+ 	soc_camera_host_unregister(&mx27_soc_camera_host);
+ 
+ 	iounmap(pcdev->base);
+@@ -765,7 +796,6 @@ static struct platform_driver mx27_camer
+ 	.remove		= __exit_p(mx27_camera_remove),
+ };
+ 
+-
+ static int __devinit mx27_camera_init(void)
+ {
+ 	return platform_driver_register(&mx27_camera_driver);
Index: patches/linux-2.6.25/generic/03_drivers_media_video_soc_camera_multiple_cameras.diff
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/03_drivers_media_video_soc_camera_multiple_cameras.diff
@@ -0,0 +1,172 @@
+Subject: soc-camera: Support multiple camera chips per host
+From: Sascha Hauer <s.hauer@pengutronix.de>
+
+soc-camera already supports more than one camera chip per host
+which can be used exclusively. This patch adds a hook for the
+board code to switch between different cameras.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+
+---
+ drivers/media/video/mt9m001.c    |    4 ++--
+ drivers/media/video/mt9v022.c    |    4 ++--
+ drivers/media/video/soc_camera.c |   20 ++++++++++++++++----
+ include/media/soc_camera.h       |    7 ++++++-
+ 4 files changed, 26 insertions(+), 9 deletions(-)
+
+Index: drivers/media/video/soc_camera.c
+===================================================================
+--- drivers/media/video/soc_camera.c.orig
++++ drivers/media/video/soc_camera.c
+@@ -212,6 +212,9 @@ static int soc_camera_open(struct inode 
+ 
+ 	icf->icd = icd;
+ 
++	if (icd->link->activate)
++		icd->link->activate(icd->link, 1);
++
+ 	/* Now we really have to activate the camera */
+ 	if (icd->use_count == 1) {
+ 		ret = ici->add(icd);
+@@ -255,6 +258,8 @@ static int soc_camera_close(struct inode
+ 
+ 	mutex_lock(&video_lock);
+ 	icd->use_count--;
++	if (icd->link->activate)
++		icd->link->activate(icd->link, 0);
+ 	if (!icd->use_count)
+ 		ici->remove(icd);
+ 	module_put(icd->ops->owner);
+@@ -654,7 +659,7 @@ static void scan_add_host(struct soc_cam
+ 	mutex_lock(&list_lock);
+ 
+ 	list_for_each_entry(icd, &devices, list) {
+-		if (icd->iface == ici->nr) {
++		if (icd->link->bus_id == ici->nr) {
+ 			icd->dev.parent = &ici->dev;
+ 			device_register_link(icd);
+ 		}
+@@ -677,7 +682,7 @@ static int scan_add_device(struct soc_ca
+ 	/* Watch out for class_for_each_device / class_find_device API by
+ 	 * Dave Young <hidave.darkstar@gmail.com> */
+ 	list_for_each_entry(ici, &hosts, list) {
+-		if (icd->iface == ici->nr) {
++		if (icd->link->bus_id == ici->nr) {
+ 			ret = 1;
+ 			icd->dev.parent = &ici->dev;
+ 			break;
+@@ -702,6 +707,9 @@ static int soc_camera_probe(struct devic
+ 	if (!icd->probe)
+ 		return -ENODEV;
+ 
++	if (icd->link->activate)
++		icd->link->activate(icd->link, 1);
++
+ 	/* We only call ->add() here to activate and probe the camera.
+ 	 * We shall ->remove() and deactivate it immediately afterwards. */
+ 	ret = ici->add(icd);
+@@ -720,6 +728,9 @@ static int soc_camera_probe(struct devic
+ 	}
+ 	ici->remove(icd);
+ 
++	if (icd->link->activate)
++		icd->link->activate(icd->link, 0);
++
+ 	return ret;
+ }
+ 
+@@ -841,7 +852,8 @@ int soc_camera_device_register(struct so
+ 	for (i = 0; i < 256 && num < 0; i++) {
+ 		num = i;
+ 		list_for_each_entry(ix, &devices, list) {
+-			if (ix->iface == icd->iface && ix->devnum == i) {
++			if (ix->link->bus_id == icd->link->bus_id &&
++					ix->devnum == i) {
+ 				num = -1;
+ 				break;
+ 			}
+@@ -856,7 +868,7 @@ int soc_camera_device_register(struct so
+ 	icd->devnum = num;
+ 	icd->dev.bus = &soc_camera_bus_type;
+ 	snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id),
+-		 "%u-%u", icd->iface, icd->devnum);
++		 "%u-%u", icd->link->bus_id, icd->devnum);
+ 
+ 	icd->dev.release = dummy_release;
+ 
+Index: include/media/soc_camera.h
+===================================================================
+--- include/media/soc_camera.h.orig
++++ include/media/soc_camera.h
+@@ -15,6 +15,8 @@
+ #include <linux/videodev2.h>
+ #include <media/videobuf-dma-sg.h>
+ 
++struct soc_camera_link;
++
+ struct soc_camera_device {
+ 	struct list_head list;
+ 	struct device dev;
+@@ -32,7 +34,7 @@ struct soc_camera_device {
+ 	unsigned short y_skip_top;	/* Lines to skip at the top */
+ 	unsigned short gain;
+ 	unsigned short exposure;
+-	unsigned char iface;		/* Host number */
++	struct soc_camera_link *link;	/* Link to this camera */
+ 	unsigned char devnum;		/* Device number per host */
+ 	unsigned char cached_datawidth;	/* See comment in .c */
+ 	struct soc_camera_ops *ops;
+@@ -74,6 +76,9 @@ struct soc_camera_link {
+ 	int bus_id;
+ 	/* GPIO number to switch between 8 and 10 bit modes */
+ 	unsigned int gpio;
++	/* (de-)activate this camera. Can be left empty if only one camera is
++	 * connected to this bus. */
++	void (*activate)(struct soc_camera_link *, int);
+ };
+ 
+ static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
+Index: drivers/media/video/mt9m001.c
+===================================================================
+--- drivers/media/video/mt9m001.c.orig
++++ drivers/media/video/mt9m001.c
+@@ -547,7 +547,7 @@ static int mt9m001_video_probe(struct so
+ 	/* We must have a parent by now. And it cannot be a wrong one.
+ 	 * So this entire test is completely redundant. */
+ 	if (!icd->dev.parent ||
+-	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
++	    to_soc_camera_host(icd->dev.parent)->nr != icd->link->bus_id)
+ 		return -ENODEV;
+ 
+ 	/* Enable the chip */
+@@ -648,7 +648,7 @@ static int mt9m001_probe(struct i2c_clie
+ 	icd->height_min	= 32;
+ 	icd->height_max	= 1024;
+ 	icd->y_skip_top	= 1;
+-	icd->iface	= icl->bus_id;
++	icd->link	= icl;
+ 	/* Default datawidth - this is the only width this camera (normally)
+ 	 * supports. It is only with extra logic that it can support
+ 	 * other widths. Therefore it seems to be a sensible default. */
+Index: drivers/media/video/mt9v022.c
+===================================================================
+--- drivers/media/video/mt9v022.c.orig
++++ drivers/media/video/mt9v022.c
+@@ -672,7 +672,7 @@ static int mt9v022_video_probe(struct so
+ 	int ret;
+ 
+ 	if (!icd->dev.parent ||
+-	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
++	    to_soc_camera_host(icd->dev.parent)->nr != icd->link->bus_id)
+ 		return -ENODEV;
+ 
+ 	/* Read out the chip version register */
+@@ -783,7 +783,7 @@ static int mt9v022_probe(struct i2c_clie
+ 	icd->height_min	= 32;
+ 	icd->height_max	= 480;
+ 	icd->y_skip_top	= 1;
+-	icd->iface	= icl->bus_id;
++	icd->link	= icl;
+ 	/* Default datawidth - this is the only width this camera (normally)
+ 	 * supports. It is only with extra logic that it can support
+ 	 * other widths. Therefore it seems to be a sensible default. */
Index: patches/linux-2.6.25/generic/04_drivers_media_video_mt9m001_fix_gpio.diff
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/04_drivers_media_video_mt9m001_fix_gpio.diff
@@ -0,0 +1,121 @@
+---
+ drivers/media/video/mt9m001.c |   31 +++++++++++++++++--------------
+ 1 file changed, 17 insertions(+), 14 deletions(-)
+
+Index: drivers/media/video/mt9m001.c
+===================================================================
+--- drivers/media/video/mt9m001.c.orig
++++ drivers/media/video/mt9m001.c
+@@ -138,6 +138,10 @@ static int mt9m001_init(struct soc_camer
+ 
+ static int mt9m001_release(struct soc_camera_device *icd)
+ {
++	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
++
++	mt9m001->datawidth = 0;
++
+ 	/* Disable the chip */
+ 	reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+ 	return 0;
+@@ -226,15 +230,12 @@ static int mt9m001_set_capture_format(st
+ 	    (flags & IS_PCLK_SAMPLE_RISING) ||
+ 	    !(flags & IS_HSYNC_ACTIVE_HIGH) ||
+ 	    !(flags & IS_VSYNC_ACTIVE_HIGH)) {
+-		printk("einval1 0x%08x\n", flags);
+ 		return -EINVAL;
+ 	}
+ 
+ 	/* Only one width bit may be set */
+-	if (!is_power_of_2(width_flag)) {
+-		printk("einval2\n");
++	if (!is_power_of_2(width_flag))
+ 		return -EINVAL;
+-	}
+ 
+ 	if ((mt9m001->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) ||
+ 	    (mt9m001->datawidth != 9  && (width_flag == IS_DATAWIDTH_9)) ||
+@@ -245,7 +246,6 @@ static int mt9m001_set_capture_format(st
+ 		ret = bus_switch_act(mt9m001,
+ 				     width_flag == IS_DATAWIDTH_8);
+ 		if (ret < 0) {
+-			printk("einval3: %d\n", ret);
+ 			return ret;
+ 		}
+ 
+@@ -281,7 +281,7 @@ static int mt9m001_set_capture_format(st
+ 				1048 + qctrl->minimum;
+ 		}
+ 	}
+-printk("out: %d\n", ret);
++
+ 	return ret < 0 ? ret : 0;
+ }
+ 
+@@ -550,6 +550,10 @@ static int mt9m001_video_probe(struct so
+ 	    to_soc_camera_host(icd->dev.parent)->nr != icd->link->bus_id)
+ 		return -ENODEV;
+ 
++	ret = bus_switch_request(mt9m001, icd->link);
++	if (ret)
++		return -ENODEV;
++
+ 	/* Enable the chip */
+ 	data = reg_write(&mt9m001->icd, MT9M001_CHIP_ENABLE, 1);
+ 	dev_dbg(&icd->dev, "write: %d\n", data);
+@@ -583,6 +587,8 @@ static int mt9m001_video_probe(struct so
+ 		goto ei2c;
+ 	}
+ 
++	ret = reg_write(icd, MT9M001_SHUTTER_WIDTH, 1049);
++
+ 	dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+ 		 data == 0x8431 ? "C12STM" : "C12ST");
+ 
+@@ -595,6 +601,8 @@ static int mt9m001_video_probe(struct so
+ 
+ eisis:
+ ei2c:
++	bus_switch_release(mt9m001);
++
+ 	return ret;
+ }
+ 
+@@ -605,6 +613,8 @@ static void mt9m001_video_remove(struct 
+ 	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
+ 		mt9m001->icd.dev.parent, mt9m001->icd.vdev);
+ 	soc_camera_video_stop(&mt9m001->icd);
++
++	bus_switch_release(mt9m001);
+ }
+ 
+ static int mt9m001_probe(struct i2c_client *client)
+@@ -655,11 +665,7 @@ static int mt9m001_probe(struct i2c_clie
+ 	mt9m001->datawidth = 10;
+ 	/* Simulated autoexposure. If enabled, we calculate shutter width
+ 	 * ourselves in the driver based on vertical blanking and frame width */
+-	mt9m001->autoexposure = 1;
+-
+-	ret = bus_switch_request(mt9m001, icl);
+-	if (ret)
+-		goto eswinit;
++	mt9m001->autoexposure = 0;
+ 
+ 	ret = soc_camera_device_register(icd);
+ 	if (ret)
+@@ -668,8 +674,6 @@ static int mt9m001_probe(struct i2c_clie
+ 	return 0;
+ 
+ eisdr:
+-	bus_switch_release(mt9m001);
+-eswinit:
+ 	kfree(mt9m001);
+ 	return ret;
+ }
+@@ -679,7 +683,6 @@ static int mt9m001_remove(struct i2c_cli
+ 	struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+ 
+ 	soc_camera_device_unregister(&mt9m001->icd);
+-	bus_switch_release(mt9m001);
+ 	kfree(mt9m001);
+ 
+ 	return 0;
Index: patches/linux-2.6.25/generic/05_drivers_media_video_mt9v022_fix_gpio.diff
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/05_drivers_media_video_mt9v022_fix_gpio.diff
@@ -0,0 +1,112 @@
+---
+ drivers/media/video/mt9v022.c |   27 +++++++++++++++------------
+ 1 file changed, 15 insertions(+), 12 deletions(-)
+
+Index: drivers/media/video/mt9v022.c
+===================================================================
+--- drivers/media/video/mt9v022.c.orig
++++ drivers/media/video/mt9v022.c
+@@ -166,7 +166,10 @@ static int mt9v022_init(struct soc_camer
+ 
+ static int mt9v022_release(struct soc_camera_device *icd)
+ {
+-	/* Nothing? */
++	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
++
++	mt9v022->datawidth = 0;
++
+ 	return 0;
+ }
+ 
+@@ -236,6 +239,7 @@ static int bus_switch_act(struct mt9v022
+ 	if (!gpio_is_valid(mt9v022->switch_gpio))
+ 		return -ENODEV;
+ 
++	printk("go8bit: %d\n", go8bit);
+ 	gpio_set_value_cansleep(mt9v022->switch_gpio, go8bit);
+ 	return 0;
+ #else
+@@ -288,9 +292,9 @@ static int mt9v022_set_capture_format(st
+ 	}
+ 	/* Setup frame format: defaults apart from width and height */
+ 	if (ret >= 0)
+-		ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
++		ret = reg_write(icd, MT9V022_COLUMN_START, rect->left + 256);
+ 	if (ret >= 0)
+-		ret = reg_write(icd, MT9V022_ROW_START, rect->top
++		ret = reg_write(icd, MT9V022_ROW_START, rect->top + 80
+ #ifdef CONFIG_MACH_MX27
+ 				+ 1
+ /*
+@@ -300,7 +304,7 @@ static int mt9v022_set_capture_format(st
+  * is a r/b one whereas http://www.siliconimaging.com/RGB%20Bayer.htm
+  * suggests it is a r/g one.
+  * The mplayer Bayer pattern works with a r/g first line whereas the
+- * mt9v022 has a r/b line as first line. On PXA this first line
++ * mt9v022 has a g/b line as first line. On PXA this first line
+  * is discarded anyway due to a bug in the PXA. On mx27 instead we cannot
+  * discard lines but only capture the whole image from the sensor, so
+  * we need this offset.
+@@ -675,6 +679,10 @@ static int mt9v022_video_probe(struct so
+ 	    to_soc_camera_host(icd->dev.parent)->nr != icd->link->bus_id)
+ 		return -ENODEV;
+ 
++	ret = bus_switch_request(mt9v022, icd->link);
++	if (ret)
++		return -ENODEV;
++
+ 	/* Read out the chip version register */
+ 	data = reg_read(icd, MT9V022_CHIP_VERSION);
+ 
+@@ -730,6 +738,7 @@ static int mt9v022_video_probe(struct so
+ 
+ eisis:
+ ei2c:
++	bus_switch_release(mt9v022);
+ 	return ret;
+ }
+ 
+@@ -740,6 +749,7 @@ static void mt9v022_video_remove(struct 
+ 	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
+ 		mt9v022->icd.dev.parent, mt9v022->icd.vdev);
+ 	soc_camera_video_stop(&mt9v022->icd);
++	bus_switch_release(mt9v022);
+ }
+ 
+ static int mt9v022_probe(struct i2c_client *client)
+@@ -782,17 +792,13 @@ static int mt9v022_probe(struct i2c_clie
+ 	icd->width_max	= 752;
+ 	icd->height_min	= 32;
+ 	icd->height_max	= 480;
+-	icd->y_skip_top	= 1;
++	icd->y_skip_top	= 0;
+ 	icd->link	= icl;
+ 	/* Default datawidth - this is the only width this camera (normally)
+ 	 * supports. It is only with extra logic that it can support
+ 	 * other widths. Therefore it seems to be a sensible default. */
+ 	mt9v022->datawidth = 10;
+ 
+-	ret = bus_switch_request(mt9v022, icl);
+-	if (ret)
+-		goto eswinit;
+-
+ 	ret = soc_camera_device_register(icd);
+ 	if (ret)
+ 		goto eisdr;
+@@ -800,8 +806,6 @@ static int mt9v022_probe(struct i2c_clie
+ 	return 0;
+ 
+ eisdr:
+-	bus_switch_release(mt9v022);
+-eswinit:
+ 	kfree(mt9v022);
+ 	return ret;
+ }
+@@ -811,7 +815,6 @@ static int mt9v022_remove(struct i2c_cli
+ 	struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+ 
+ 	soc_camera_device_unregister(&mt9v022->icd);
+-	bus_switch_release(mt9v022);
+ 	kfree(mt9v022);
+ 
+ 	return 0;
Index: patches/linux-2.6.25/generic/06_phytec_pcm970_baseboard_camera_fixes.diff
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/06_phytec_pcm970_baseboard_camera_fixes.diff
@@ -0,0 +1,20 @@
+---
+ arch/arm/mach-mx2/pcm970-baseboard.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+Index: arch/arm/mach-mx2/pcm970-baseboard.c
+===================================================================
+--- arch/arm/mach-mx2/pcm970-baseboard.c.orig
++++ arch/arm/mach-mx2/pcm970-baseboard.c
+@@ -159,8 +159,9 @@ static int pcm970_camera_exit(struct pla
+ struct mx27_camera_platform_data pcm970_camera = {
+ 	.init = pcm970_camera_init,
+ 	.exit = pcm970_camera_exit,
+-	.clk  = 48000000,
+-	.flags = MX27_CAMERA_HSYNC_HIGH | MX27_CAMERA_GATED_CLOCK,
++	.clk  = 26600000,
++	.flags = MX27_CAMERA_HSYNC_HIGH | MX27_CAMERA_GATED_CLOCK |
++		MX27_CAMERA_EXT_VSYNC,
+ };
+ 
+ /*
Index: patches/linux-2.6.25/generic/serial-imx-25-26.diff
===================================================================
--- /dev/null
+++ patches/linux-2.6.25/generic/serial-imx-25-26.diff
@@ -0,0 +1,749 @@
+---
+ arch/arm/mach-mx2/serial.c |  112 ++++++++----
+ drivers/serial/imx.c       |  400 ++++++++++++---------------------------------
+ 2 files changed, 184 insertions(+), 328 deletions(-)
+
+Index: arch/arm/mach-mx2/serial.c
+===================================================================
+--- arch/arm/mach-mx2/serial.c.orig
++++ arch/arm/mach-mx2/serial.c
+@@ -13,7 +13,8 @@
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
+  */
+ 
+ #include <linux/module.h>
+@@ -21,84 +22,119 @@
+ #include <linux/serial.h>
+ #include <asm/hardware.h>
+ #include <asm/arch/imx-uart.h>
+-#include "devices.h"
+ 
+-static struct resource uart0 = {
+-	.start = UART1_BASE_ADDR,
+-	.end = UART1_BASE_ADDR + 0x0B5,
+-	.flags = IORESOURCE_MEM
++static struct resource uart0[] = {
++	{
++		.start = UART1_BASE_ADDR,
++		.end = UART1_BASE_ADDR + 0x0B5,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = INT_UART1,
++		.end = INT_UART1,
++		.flags = IORESOURCE_IRQ,
++	},
+ };
+ 
+ static struct platform_device mxc_uart_device0 = {
+ 	.name = "imx-uart",
+ 	.id = 0,
+-	.resource = &uart0,
+-	.num_resources = 1,
++	.resource = uart0,
++	.num_resources = ARRAY_SIZE(uart0),
+ };
+ 
+-static struct resource uart1 = {
+-	.start = UART2_BASE_ADDR,
+-	.end = UART2_BASE_ADDR + 0x0B5,
+-	.flags = IORESOURCE_MEM
++static struct resource uart1[] = {
++	{
++		.start = UART2_BASE_ADDR,
++		.end = UART2_BASE_ADDR + 0x0B5,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = INT_UART2,
++		.end = INT_UART2,
++		.flags = IORESOURCE_IRQ,
++	},
+ };
+ 
+ static struct platform_device mxc_uart_device1 = {
+ 	.name = "imx-uart",
+ 	.id = 1,
+-	.resource = &uart1,
+-	.num_resources = 1,
++	.resource = uart1,
++	.num_resources = ARRAY_SIZE(uart1),
+ };
+ 
+-static struct resource uart2 = {
+-	.start = UART3_BASE_ADDR,
+-	.end = UART3_BASE_ADDR + 0x0B5,
+-	.flags = IORESOURCE_MEM
++static struct resource uart2[] = {
++	{
++		.start = UART3_BASE_ADDR,
++		.end = UART3_BASE_ADDR + 0x0B5,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = INT_UART3,
++		.end = INT_UART3,
++		.flags = IORESOURCE_IRQ,
++	},
+ };
+ 
+ static struct platform_device mxc_uart_device2 = {
+ 	.name = "imx-uart",
+ 	.id = 2,
+-	.resource = &uart2,
+-	.num_resources = 1,
++	.resource = uart2,
++	.num_resources = ARRAY_SIZE(uart2),
+ };
+ 
+-static struct resource uart3 = {
+-	.start = UART4_BASE_ADDR,
+-	.end = UART4_BASE_ADDR + 0x0B5,
+-	.flags = IORESOURCE_MEM
++static struct resource uart3[] = {
++	{
++		.start = UART4_BASE_ADDR,
++		.end = UART4_BASE_ADDR + 0x0B5,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = INT_UART4,
++		.end = INT_UART4,
++		.flags = IORESOURCE_IRQ,
++	},
+ };
+ 
+ static struct platform_device mxc_uart_device3 = {
+ 	.name = "imx-uart",
+ 	.id = 3,
+-	.resource = &uart3,
+-	.num_resources = 1,
++	.resource = uart3,
++	.num_resources = ARRAY_SIZE(uart3),
+ };
+ 
+-static struct resource uart4 = {
+-	.start = UART5_BASE_ADDR,
+-	.end = UART5_BASE_ADDR + 0x0B5,
+-	.flags = IORESOURCE_MEM
++static struct resource uart4[] = {
++	{
++		.start = UART5_BASE_ADDR,
++		.end = UART5_BASE_ADDR + 0x0B5,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = INT_UART5,
++		.end = INT_UART5,
++		.flags = IORESOURCE_IRQ,
++	},
+ };
+ 
+ static struct platform_device mxc_uart_device4 = {
+ 	.name = "imx-uart",
+ 	.id = 4,
+-	.resource = &uart4,
+-	.num_resources = 1,
++	.resource = uart4,
++	.num_resources = ARRAY_SIZE(uart4),
+ };
+ 
+-static struct resource uart5 = {
+-	.start = UART6_BASE_ADDR,
+-	.end = UART6_BASE_ADDR + 0x0B5,
+-	.flags = IORESOURCE_MEM
++static struct resource uart5[] = {
++	{
++		.start = UART6_BASE_ADDR,
++		.end = UART6_BASE_ADDR + 0x0B5,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = INT_UART6,
++		.end = INT_UART6,
++		.flags = IORESOURCE_IRQ,
++	},
+ };
+ 
+ static struct platform_device mxc_uart_device5 = {
+ 	.name = "imx-uart",
+ 	.id = 5,
+-	.resource = &uart5,
+-	.num_resources = 1,
++	.resource = uart5,
++	.num_resources = ARRAY_SIZE(uart5),
+ };
+ 
+ /*
+Index: drivers/serial/imx.c
+===================================================================
+--- drivers/serial/imx.c.orig
++++ drivers/serial/imx.c
+@@ -62,7 +62,7 @@
+ #define UBIR  0xa4 /* BRM Incremental Register */
+ #define UBMR  0xa8 /* BRM Modulator Register */
+ #define UBRC  0xac /* Baud Rate Count Register */
+-#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
++#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
+ #define ONEMS 0xb0 /* One Millisecond register */
+ #define UTS   0xb4 /* UART Test Register */
+ #endif
+@@ -99,7 +99,7 @@
+ #ifdef CONFIG_ARCH_IMX
+ #define  UCR1_UARTCLKEN  (1<<2)	 /* UART clock enabled */
+ #endif
+-#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
++#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
+ #define  UCR1_UARTCLKEN  (0)	 /* not present on mx2/mx3 */
+ #endif
+ #define  UCR1_DOZE       (1<<1)	 /* Doze */
+@@ -182,11 +182,10 @@
+ #define MAX_INTERNAL_IRQ	IMX_IRQS
+ #endif
+ 
+-#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
++#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
+ #define SERIAL_IMX_MAJOR        207
+ #define MINOR_START	        16
+ #define DEV_NAME		"ttymxc"
+-#define MX3_UART_REFFREQ	64000000
+ #define MAX_INTERNAL_IRQ	MXC_MAX_INT_LINES
+ #endif
+ 
+@@ -200,6 +199,8 @@
+ 
+ #define DRIVER_NAME "IMX-uart"
+ 
++#define UART_NR 8
++
+ struct imx_port {
+ 	struct uart_port	port;
+ 	struct timer_list	timer;
+@@ -207,22 +208,8 @@ struct imx_port {
+ 	int			txirq,rxirq,rtsirq;
+ 	int			have_rtscts:1;
+ 	struct clk		*clk;
+-	const char		*clk_name;
+ };
+ 
+-static int imx_uart_get_perclk(struct imx_port *sport)
+-{
+-#ifdef CONFIG_ARCH_IMX
+-	return imx_get_perclk1();
+-#endif
+-#ifdef CONFIG_ARCH_MX2
+-	return clk_get_rate(sport->clk);
+-#endif
+-#ifdef CONFIG_ARCH_MX3
+-	return MX3_UART_REFFREQ; /* FIXME */
+-#endif
+-}
+-
+ /*
+  * Handle any change of modem status signal since we were last called.
+  */
+@@ -531,16 +518,13 @@ static int imx_setup_ufcr(struct imx_por
+ {
+ 	unsigned int val;
+ 	unsigned int ufcr_rfdiv;
+-	unsigned int reffreq;
+ 
+ 	/* set receiver / transmitter trigger level.
+ 	 * RFDIV is set such way to satisfy requested uartclk value
+ 	 */
+ 	val = TXTL << 10 | RXTL;
+-
+-	reffreq = imx_uart_get_perclk(sport);
+-
+-	ufcr_rfdiv = (reffreq + sport->port.uartclk / 2) / sport->port.uartclk;
++	ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
++			/ sport->port.uartclk;
+ 
+ 	if(!ufcr_rfdiv)
+ 		ufcr_rfdiv = 1;
+@@ -572,9 +556,10 @@ static int imx_startup(struct uart_port 
+ 	writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
+ 
+ 	/*
+-	 * Allocate the IRQ
++	 * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
++	 * chips only have one interrupt.
+ 	 */
+-	if (sport->rxirq) {
++	if (sport->txirq > 0) {
+ 		retval = request_irq(sport->rxirq, imx_rxint, 0,
+ 				DRIVER_NAME, sport);
+ 		if (retval)
+@@ -645,7 +630,7 @@ static void imx_shutdown(struct uart_por
+ 	/*
+ 	 * Free the interrupts
+ 	 */
+-	if (sport->rxirq) {
++	if (sport->txirq > 0) {
+ 		free_irq(sport->rtsirq, sport);
+ 		free_irq(sport->txirq, sport);
+ 		free_irq(sport->rxirq, sport);
+@@ -669,7 +654,6 @@ imx_set_termios(struct uart_port *port, 
+ 	unsigned long flags;
+ 	unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
+ 	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+-	unsigned int per_clk = imx_uart_get_perclk(sport);
+ 	unsigned int div, num, denom, ufcr;
+ 
+ 	/*
+@@ -716,7 +700,7 @@ imx_set_termios(struct uart_port *port, 
+ 	/*
+ 	 * Ask the core to calculate the divisor for us.
+ 	 */
+-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
++	baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+ 	quot = uart_get_divisor(port, baud);
+ 
+ 	spin_lock_irqsave(&sport->port.lock, flags);
+@@ -766,26 +750,40 @@ imx_set_termios(struct uart_port *port, 
+ 			sport->port.membase + UCR2);
+ 	old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
+ 
+-	div = per_clk / ((baud * 16) + 1000);
+-	if (div > 6)
+-		div = 6;
+-
+-	sport->port.uartclk = per_clk / div;
+-
+-	num = (baud / 100) - 1;
+-	denom = (sport->port.uartclk / 1600) - 1;
+-	if ((denom < 65536) && (sport->port.uartclk > 1600)) {
+-		writel(num, sport->port.membase + UBIR);
+-		writel(denom, sport->port.membase + UBMR);
++	div = sport->port.uartclk / (baud * 16);
++	if (div > 7)
++		div = 7;
++	if (!div)
++		div = 1;
++
++	num = baud;
++	denom = port->uartclk / div / 16;
++
++	/* shift num and denom right until they fit into 16 bits */
++	while (num > 0x10000 || denom > 0x10000) {
++		num >>= 1;
++		denom >>= 1;
+ 	}
++	if (num > 0)
++		num -= 1;
++	if (denom > 0)
++		denom -= 1;
++
++	writel(num, sport->port.membase + UBIR);
++	writel(denom, sport->port.membase + UBMR);
++
++	if (div == 7)
++		div = 6; /* 6 in RFDIV means divide by 7 */
++	else
++		div = 6 - div;
+ 
+ 	ufcr = readl(sport->port.membase + UFCR);
+ 	ufcr = (ufcr & (~UFCR_RFDIV)) |
+-	    ((6 - div) << 7);
++	    (div << 7);
+ 	writel(ufcr, sport->port.membase + UFCR);
+ 
+ #ifdef ONEMS
+-	writel(per_clk / 1000, sport->port.membase + ONEMS);
++	writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS);
+ #endif
+ 
+ 	writel(old_ucr1, sport->port.membase + UCR1);
+@@ -896,228 +894,7 @@ static struct uart_ops imx_pops = {
+ 	.verify_port	= imx_verify_port,
+ };
+ 
+-#ifdef CONFIG_ARCH_IMX
+-static struct imx_port imx_ports[] = {
+-	{
+-	.txirq  = UART1_MINT_TX,
+-	.rxirq  = UART1_MINT_RX,
+-	.rtsirq = UART1_MINT_RTS,
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IMX_UART1_BASE,
+-		.mapbase	= 0x00206000,
+-		.irq		= UART1_MINT_RX,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 0,
+-	},
+-	}, {
+-	.txirq  = UART2_MINT_TX,
+-	.rxirq  = UART2_MINT_RX,
+-	.rtsirq = UART2_MINT_RTS,
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IMX_UART2_BASE,
+-		.mapbase	= 0x00207000,
+-		.irq		= UART2_MINT_RX,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 1,
+-	},
+-	}
+-};
+-#endif
+-
+-#ifdef CONFIG_ARCH_MX2
+-static struct imx_port imx_ports[] = {
+-	{
+-	.clk_name = "uart_clk.0",
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART1_BASE_ADDR),
+-		.mapbase	= UART1_BASE_ADDR,
+-		.irq		= INT_UART1,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 0,
+-	},
+-	}, {
+-	.clk_name = "uart_clk.1",
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART2_BASE_ADDR),
+-		.mapbase	= UART2_BASE_ADDR,
+-		.irq		= INT_UART2,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 1,
+-	},
+-	}, {
+-	.clk_name = "uart_clk.2",
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART3_BASE_ADDR),
+-		.mapbase	= UART3_BASE_ADDR,
+-		.irq		= INT_UART3,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 2,
+-	},
+-	}, {
+-	.clk_name = "uart_clk.3",
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART4_BASE_ADDR),
+-		.mapbase	= UART4_BASE_ADDR,
+-		.irq		= INT_UART4,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 3,
+-	},
+-	}, {
+-	.clk_name = "uart_clk.4",
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART5_BASE_ADDR),
+-		.mapbase	= UART5_BASE_ADDR,
+-		.irq		= INT_UART5,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 4,
+-	},
+-	}, {
+-	.clk_name = "uart_clk.5",
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART6_BASE_ADDR),
+-		.mapbase	= UART6_BASE_ADDR,
+-		.irq		= INT_UART6,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 5,
+-	},
+-	}
+-};
+-#endif
+-
+-#ifdef CONFIG_ARCH_MX3
+-static struct imx_port imx_ports[] = {
+-	{
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART1_BASE_ADDR),
+-		.mapbase	= UART1_BASE_ADDR,
+-		.irq		= MXC_INT_UART1,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 0,
+-	},
+-	}, {
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART2_BASE_ADDR),
+-		.mapbase	= UART2_BASE_ADDR,
+-		.irq		= MXC_INT_UART2,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 1,
+-	},
+-	}, {
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART3_BASE_ADDR),
+-		.mapbase	= UART3_BASE_ADDR,
+-		.irq		= MXC_INT_UART3,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 2,
+-	},
+-	}, {
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART4_BASE_ADDR),
+-		.mapbase	= UART4_BASE_ADDR,
+-		.irq		= MXC_INT_UART4,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 3,
+-	},
+-	}, {
+-	.port	= {
+-		.type		= PORT_IMX,
+-		.iotype		= UPIO_MEM,
+-		.membase	= (void *)IO_ADDRESS(UART5_BASE_ADDR),
+-		.mapbase	= UART5_BASE_ADDR,
+-		.irq		= MXC_INT_UART5,
+-		.uartclk	= 16000000,
+-		.fifosize	= 32,
+-		.flags		= UPF_BOOT_AUTOCONF,
+-		.ops		= &imx_pops,
+-		.line		= 4,
+-	},
+-	}
+-};
+-#endif
+-
+-/*
+- * Setup the IMX serial ports.
+- * Note also that we support "console=ttySMXx" where "x" is either 0 or 1.
+- * Which serial port this ends up being depends on the machine you're
+- * running this kernel on.  I'm not convinced that this is a good idea,
+- * but that's the way it traditionally works.
+- *
+- */
+-static void __init imx_init_ports(void)
+-{
+-	static int first = 1;
+-	int i;
+-
+-	if (!first)
+-		return;
+-	first = 0;
+-
+-	for (i = 0; i < ARRAY_SIZE(imx_ports); i++) {
+-		init_timer(&imx_ports[i].timer);
+-		imx_ports[i].timer.function = imx_timeout;
+-		imx_ports[i].timer.data     = (unsigned long)&imx_ports[i];
+-	}
+-}
++static struct imx_port *imx_ports[UART_NR];
+ 
+ #ifdef CONFIG_SERIAL_IMX_CONSOLE
+ static void imx_console_putchar(struct uart_port *port, int ch)
+@@ -1136,7 +913,7 @@ static void imx_console_putchar(struct u
+ static void
+ imx_console_write(struct console *co, const char *s, unsigned int count)
+ {
+-	struct imx_port *sport = &imx_ports[co->index];
++	struct imx_port *sport = imx_ports[co->index];
+ 	unsigned int old_ucr1, old_ucr2;
+ 
+ 	/*
+@@ -1202,8 +979,7 @@ imx_console_get_options(struct imx_port 
+ 		else
+ 			ucfr_rfdiv = 6 - ucfr_rfdiv;
+ 
+-
+-		uartclk = imx_uart_get_perclk(sport);
++		uartclk = clk_get_rate(sport->clk);
+ 		uartclk /= ucfr_rfdiv;
+ 
+ 		{	/*
+@@ -1243,13 +1019,8 @@ imx_console_setup(struct console *co, ch
+ 	 */
+ 	if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
+ 		co->index = 0;
+-	sport = &imx_ports[co->index];
+-#ifdef CONFIG_ARCH_MX2
+-	if (sport->clk_name) {
+-		sport->clk = clk_get(NULL, sport->clk_name);
+-		clk_enable(sport->clk);
+-	}
+-#endif
++	sport = imx_ports[co->index];
++
+ 	if (options)
+ 		uart_parse_options(options, &baud, &parity, &bits, &flow);
+ 	else
+@@ -1271,14 +1042,6 @@ static struct console imx_console = {
+ 	.data		= &imx_reg,
+ };
+ 
+-static int __init imx_rs_console_init(void)
+-{
+-	imx_init_ports();
+-	register_console(&imx_console);
+-	return 0;
+-}
+-console_initcall(imx_rs_console_init);
+-
+ #define IMX_CONSOLE	&imx_console
+ #else
+ #define IMX_CONSOLE	NULL
+@@ -1316,21 +1079,73 @@ static int serial_imx_resume(struct plat
+ 
+ static int serial_imx_probe(struct platform_device *pdev)
+ {
++	struct imx_port *sport;
+ 	struct imxuart_platform_data *pdata;
++	void __iomem *base;
++	int ret = 0;
++	struct resource *res;
++
++	sport = kzalloc(sizeof(*sport), GFP_KERNEL);
++	if (!sport)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		ret = -ENODEV;
++		goto free;
++	}
++
++	base = ioremap(res->start, PAGE_SIZE);
++	if (!base) {
++		ret = -ENOMEM;
++		goto free;
++	}
+ 
+-	imx_ports[pdev->id].port.dev = &pdev->dev;
++	sport->port.dev = &pdev->dev;
++	sport->port.mapbase = res->start;
++	sport->port.membase = base;
++	sport->port.type = PORT_IMX,
++	sport->port.iotype = UPIO_MEM;
++	sport->port.irq = platform_get_irq(pdev, 0);
++	sport->rxirq = platform_get_irq(pdev, 0);
++	sport->txirq = platform_get_irq(pdev, 1);
++	sport->rtsirq = platform_get_irq(pdev, 2);
++	sport->port.fifosize = 32;
++	sport->port.ops = &imx_pops;
++	sport->port.flags = UPF_BOOT_AUTOCONF;
++	sport->port.line = pdev->id;
++	init_timer(&sport->timer);
++	sport->timer.function = imx_timeout;
++	sport->timer.data     = (unsigned long)sport;
++
++	sport->clk = clk_get(&pdev->dev, "uart_clk");
++	if (IS_ERR(sport->clk)) {
++		ret = PTR_ERR(sport->clk);
++		goto unmap;
++	}
++	clk_enable(sport->clk);
++
++	sport->port.uartclk = clk_get_rate(sport->clk);
++
++	imx_ports[pdev->id] = sport;
+ 
+-	pdata = (struct imxuart_platform_data *)pdev->dev.platform_data;
++	pdata = pdev->dev.platform_data;
+ 	if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
+-		imx_ports[pdev->id].have_rtscts = 1;
++		sport->have_rtscts = 1;
+ 
+ 	if (pdata->init)
+ 		pdata->init(pdev);
+ 
+-	uart_add_one_port(&imx_reg, &imx_ports[pdev->id].port);
+-	platform_set_drvdata(pdev, &imx_ports[pdev->id]);
++	uart_add_one_port(&imx_reg, &sport->port);
++	platform_set_drvdata(pdev, &sport->port);
+ 
+ 	return 0;
++unmap:
++	iounmap(sport->port.membase);
++free:
++	kfree(sport);
++
++	return ret;
+ }
+ 
+ static int serial_imx_remove(struct platform_device *pdev)
+@@ -1338,16 +1153,23 @@ static int serial_imx_remove(struct plat
+ 	struct imxuart_platform_data *pdata;
+ 	struct imx_port *sport = platform_get_drvdata(pdev);
+ 
+-	pdata = (struct imxuart_platform_data *)pdev->dev.platform_data;
++	pdata = pdev->dev.platform_data;
+ 
+ 	platform_set_drvdata(pdev, NULL);
+ 
+-	if (sport)
++	if (sport) {
+ 		uart_remove_one_port(&imx_reg, &sport->port);
++		clk_put(sport->clk);
++	}
++
++	clk_disable(sport->clk);
+ 
+ 	if (pdata->exit)
+ 		pdata->exit(pdev);
+ 
++	iounmap(sport->port.membase);
++	kfree(sport);
++
+ 	return 0;
+ }
+ 
+@@ -1369,8 +1191,6 @@ static int __init imx_serial_init(void)
+ 
+ 	printk(KERN_INFO "Serial: IMX driver\n");
+ 
+-	imx_init_ports();
+-
+ 	ret = uart_register_driver(&imx_reg);
+ 	if (ret)
+ 		return ret;
Index: patches/linux-2.6.25/generic/series
===================================================================
--- patches/linux-2.6.25/generic/series.orig
+++ patches/linux-2.6.25/generic/series
@@ -117,3 +117,17 @@ fix_gpio_calculation_failure.diff -p0
 
 # left a odour mark
 version.diff -p0
+
+# fixup camera handling
+01_mxc_irq_priority.diff -p0
+02_mx2_camera_driver_fixes.diff -p0
+03_drivers_media_video_soc_camera_multiple_cameras.diff -p0
+04_drivers_media_video_mt9m001_fix_gpio.diff -p0
+05_drivers_media_video_mt9v022_fix_gpio.diff -p0
+06_phytec_pcm970_baseboard_camera_fixes.diff -p0
+
+# fixup serial
+serial-imx-25-26.diff -p0
+0001--ARM-serial-imx-set-RXD-mux-bit-on-i.MX27-and-i.MX.patch -p0
+0002--ARM-serial-imx-fix-rts-handling-for-non-imx1-base.patch -p0
+0003--ARM-pcm038-fix-uart2-pin-definitions.patch -p0
Index: ptxconfig
===================================================================
--- ptxconfig.orig
+++ ptxconfig
@@ -11,7 +11,7 @@ PTXCONF_BUILD_USERLAND=y
 # Project Name & Version           
 #
 PTXCONF_PROJECT="phyCORE-i.MX27"
-PTXCONF_PROJECT_VERSION="-6"
+PTXCONF_PROJECT_VERSION="-6.3"
 PTXCONF_PHYCORE_I_MX27=y
 
 #
