uart: pl011: Add support to ZTE uart

Message ID 1426234447-6061-1-git-send-email-jun.nie@linaro.org
State New
Headers show

Commit Message

Jun Nie March 13, 2015, 8:14 a.m.
Support ZTE uart with modifying some registers offset
and probe as platform device for AMBA IP ID is not
available on ZTE uart.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
 Documentation/devicetree/bindings/serial/pl011.txt |   2 +-
 drivers/tty/serial/Kconfig                         |   4 +-
 drivers/tty/serial/amba-pl011.c                    | 416 ++++++++++++++++-----
 include/linux/amba/serial.h                        |  16 +
 4 files changed, 341 insertions(+), 97 deletions(-)

Comments

Shawn Guo March 16, 2015, 1:42 a.m. | #1
On Fri, Mar 13, 2015 at 04:48:50PM +0000, Andrew Jackson wrote:
> > +static int zx_uart_remove(struct platform_device *pdev)
> > +{
> > +       struct uart_amba_port *uap = platform_get_drvdata(pdev);
> > +       int i;
> > +
> > +       uart_remove_one_port(&amba_reg, &uap->port);
> > +
> > +       for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
> > +               if (amba_ports[i] == uap)
> > +                       amba_ports[i] = NULL;
> > +
> > +       pl011_dma_remove(uap);
> > +       return 0;
> > +}
> 
> Since the references to zx_uart_probe and zx_uart_remove are conditionally compiled,
> you should also so bracket them here to avoid complaints about unused functions.

Right, the comment applies to pl011_probe and pl011_remove as well.
Compiling the driver for zx_uart, I got the following warnings.

  CC      drivers/tty/serial/amba-pl011.o
../drivers/tty/serial/amba-pl011.c:2259:12: warning: ‘pl011_probe’ defined but not used [-Wunused-function]
../drivers/tty/serial/amba-pl011.c:2345:12: warning: ‘pl011_remove’ defined but not used [-Wunused-function]
../drivers/tty/serial/amba-pl011.c:2490:23: warning: ‘pl011_ids’ defined but not used [-Wunused-variable]

Shawn
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shawn Guo March 16, 2015, 8:26 a.m. | #2
On Fri, Mar 13, 2015 at 04:14:07PM +0800, Jun Nie wrote:
> Support ZTE uart with modifying some registers offset
> and probe as platform device for AMBA IP ID is not
> available on ZTE uart.
> 
> Signed-off-by: Jun Nie <jun.nie@linaro.org>

Boot console seems working fine, but serial console doesn't.  I'm
booting the kernel into an initramfs and the console is not working.

Have you verified the serial console is actually working?

Shawn
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch hide | download patch | download mbox

diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt
index ba3ecb8..cbae3d9 100644
--- a/Documentation/devicetree/bindings/serial/pl011.txt
+++ b/Documentation/devicetree/bindings/serial/pl011.txt
@@ -1,7 +1,7 @@ 
 * ARM AMBA Primecell PL011 serial UART
 
 Required properties:
-- compatible: must be "arm,primecell", "arm,pl011"
+- compatible: must be "arm,primecell", "arm,pl011", "zte,zx296702-uart"
 - reg: exactly one register range with length 0x1000
 - interrupts: exactly one interrupt specifier
 
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index d2501f0..982ca78 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -47,12 +47,12 @@  config SERIAL_AMBA_PL010_CONSOLE
 
 config SERIAL_AMBA_PL011
 	tristate "ARM AMBA PL011 serial port support"
-	depends on ARM_AMBA
+	depends on ARM_AMBA || SOC_ZX296702
 	select SERIAL_CORE
 	help
 	  This selects the ARM(R) AMBA(R) PrimeCell PL011 UART.  If you have
 	  an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
-	  here.
+	  here. Say yes if you have SOC_ZX296702.
 
 	  If unsure, say N.
 
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8d94c19..e641678 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -72,6 +72,18 @@ 
 
 /* There is by now at least one vendor with differing details, so handle it */
 struct vendor_data {
+	unsigned int		dr;
+	unsigned int		fr;
+	unsigned int		u1_cr;
+	unsigned int		u1_ifls;
+	unsigned int		u1_imsc;
+	unsigned int		u1_mis;
+	unsigned int		u1_icr;
+	unsigned int		u1_dmacr;
+	unsigned int		fr_busy;
+	unsigned int		fr_dsr;
+	unsigned int		fr_cts;
+	unsigned int		u1_fr_ri;
 	unsigned int		ifls;
 	unsigned int		lcrh_tx;
 	unsigned int		lcrh_rx;
@@ -88,6 +100,18 @@  static unsigned int get_fifosize_arm(struct amba_device *dev)
 }
 
 static struct vendor_data vendor_arm = {
+	.dr			= UART01x_DR,
+	.fr			= UART01x_FR,
+	.u1_cr			= UART011_CR,
+	.u1_ifls		= UART011_IFLS,
+	.u1_imsc		= UART011_IMSC,
+	.u1_mis			= UART011_MIS,
+	.u1_icr			= UART011_ICR,
+	.u1_dmacr		= UART011_DMACR,
+	.fr_busy		= UART01x_FR_BUSY,
+	.fr_dsr			= UART01x_FR_DSR,
+	.fr_cts			= UART01x_FR_CTS,
+	.u1_fr_ri		= UART011_FR_RI,
 	.ifls			= UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
 	.lcrh_tx		= UART011_LCRH,
 	.lcrh_rx		= UART011_LCRH,
@@ -97,12 +121,51 @@  static struct vendor_data vendor_arm = {
 	.get_fifosize		= get_fifosize_arm,
 };
 
+static unsigned int get_fifosize_zx(struct amba_device *dev)
+{
+	return 16;
+}
+
+static struct vendor_data vendor_zx = {
+	.dr			= ZX_UART01x_DR,
+	.fr			= ZX_UART01x_FR,
+	.u1_cr			= ZX_UART011_CR,
+	.u1_ifls		= ZX_UART011_IFLS,
+	.u1_imsc		= ZX_UART011_IMSC,
+	.u1_mis			= ZX_UART011_MIS,
+	.u1_icr			= ZX_UART011_ICR,
+	.u1_dmacr		= ZX_UART011_DMACR,
+	.fr_busy		= ZX_UART01x_FR_BUSY,
+	.fr_dsr			= ZX_UART01x_FR_DSR,
+	.fr_cts			= ZX_UART01x_FR_CTS,
+	.u1_fr_ri		= ZX_UART011_FR_RI,
+	.ifls			= UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+	.lcrh_tx		= UART011_LCRH,
+	.lcrh_rx		= UART011_LCRH,
+	.oversampling		= false,
+	.dma_threshold		= false,
+	.cts_event_workaround	= false,
+	.get_fifosize		= get_fifosize_zx,
+};
+
 static unsigned int get_fifosize_st(struct amba_device *dev)
 {
 	return 64;
 }
 
 static struct vendor_data vendor_st = {
+	.dr			= UART01x_DR,
+	.fr			= UART01x_FR,
+	.u1_cr			= UART011_CR,
+	.u1_ifls		= UART011_IFLS,
+	.u1_imsc		= UART011_IMSC,
+	.u1_mis			= UART011_MIS,
+	.u1_icr			= UART011_ICR,
+	.u1_dmacr		= UART011_DMACR,
+	.fr_busy		= UART01x_FR_BUSY,
+	.fr_dsr			= UART01x_FR_DSR,
+	.fr_cts			= UART01x_FR_CTS,
+	.u1_fr_ri		= UART011_FR_RI,
 	.ifls			= UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
 	.lcrh_tx		= ST_UART011_LCRH_TX,
 	.lcrh_rx		= ST_UART011_LCRH_RX,
@@ -155,6 +218,18 @@  struct uart_amba_port {
 	unsigned int		fifosize;	/* vendor-specific */
 	unsigned int		lcrh_tx;	/* vendor-specific */
 	unsigned int		lcrh_rx;	/* vendor-specific */
+	unsigned int		dr;		/* vendor-specific */
+	unsigned int		fr;             /* vendor-specific */
+	unsigned int		u1_cr;          /* vendor-specific */
+	unsigned int		u1_ifls;	/* vendor-specific */
+	unsigned int		u1_imsc;        /* vendor-specific */
+	unsigned int		u1_mis;         /* vendor-specific */
+	unsigned int		u1_icr;         /* vendor-specific */
+	unsigned int		u1_dmacr;       /* vendor-specific */
+	unsigned int		fr_busy;        /* vendor-specific */
+	unsigned int		fr_dsr;		/* vendor-specific */
+	unsigned int		fr_cts;         /* vendor-specific */
+	unsigned int		u1_fr_ri;       /* vendor-specific */
 	unsigned int		old_cr;		/* state during shutdown */
 	bool			autorts;
 	char			type[12];
@@ -179,12 +254,12 @@  static int pl011_fifo_to_tty(struct uart_amba_port *uap)
 	int fifotaken = 0;
 
 	while (max_count--) {
-		status = readw(uap->port.membase + UART01x_FR);
+		status = readw(uap->port.membase + uap->fr);
 		if (status & UART01x_FR_RXFE)
 			break;
 
 		/* Take chars from the FIFO and update status */
-		ch = readw(uap->port.membase + UART01x_DR) |
+		ch = readw(uap->port.membase + uap->dr) |
 			UART_DUMMY_DR_RX;
 		flag = TTY_NORMAL;
 		uap->port.icount.rx++;
@@ -266,7 +341,7 @@  static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
 	/* DMA is the sole user of the platform data right now */
 	struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
 	struct dma_slave_config tx_conf = {
-		.dst_addr = uap->port.mapbase + UART01x_DR,
+		.dst_addr = uap->port.mapbase + uap->dr,
 		.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
 		.direction = DMA_MEM_TO_DEV,
 		.dst_maxburst = uap->fifosize >> 1,
@@ -316,7 +391,7 @@  static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
 
 	if (chan) {
 		struct dma_slave_config rx_conf = {
-			.src_addr = uap->port.mapbase + UART01x_DR,
+			.src_addr = uap->port.mapbase + uap->dr,
 			.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
 			.direction = DMA_DEV_TO_MEM,
 			.src_maxburst = uap->fifosize >> 2,
@@ -461,7 +536,7 @@  static void pl011_dma_tx_callback(void *data)
 
 	dmacr = uap->dmacr;
 	uap->dmacr = dmacr & ~UART011_TXDMAE;
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 
 	/*
 	 * If TX DMA was disabled, it means that we've stopped the DMA for
@@ -485,7 +560,7 @@  static void pl011_dma_tx_callback(void *data)
 		 * have data pending to be sent.  Re-enable the TX IRQ.
 		 */
 		uap->im |= UART011_TXIM;
-		writew(uap->im, uap->port.membase + UART011_IMSC);
+		writew(uap->im, uap->port.membase + uap->u1_imsc);
 	}
 	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
@@ -576,7 +651,7 @@  static int pl011_dma_tx_refill(struct uart_amba_port *uap)
 	dma_dev->device_issue_pending(chan);
 
 	uap->dmacr |= UART011_TXDMAE;
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 	uap->dmatx.queued = true;
 
 	/*
@@ -612,9 +687,9 @@  static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
 	 */
 	if (uap->dmatx.queued) {
 		uap->dmacr |= UART011_TXDMAE;
-		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+		writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 		uap->im &= ~UART011_TXIM;
-		writew(uap->im, uap->port.membase + UART011_IMSC);
+		writew(uap->im, uap->port.membase + uap->u1_imsc);
 		return true;
 	}
 
@@ -624,7 +699,7 @@  static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
 	 */
 	if (pl011_dma_tx_refill(uap) > 0) {
 		uap->im &= ~UART011_TXIM;
-		writew(uap->im, uap->port.membase + UART011_IMSC);
+		writew(uap->im, uap->port.membase + uap->u1_imsc);
 		return true;
 	}
 	return false;
@@ -638,7 +713,7 @@  static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
 {
 	if (uap->dmatx.queued) {
 		uap->dmacr &= ~UART011_TXDMAE;
-		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+		writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 	}
 }
 
@@ -669,11 +744,11 @@  static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
 				uap->im |= UART011_TXIM;
 				ret = false;
 			}
-			writew(uap->im, uap->port.membase + UART011_IMSC);
+			writew(uap->im, uap->port.membase + uap->u1_imsc);
 		} else if (!(uap->dmacr & UART011_TXDMAE)) {
 			uap->dmacr |= UART011_TXDMAE;
 			writew(uap->dmacr,
-				       uap->port.membase + UART011_DMACR);
+				       uap->port.membase + uap->u1_dmacr);
 		}
 		return ret;
 	}
@@ -684,9 +759,9 @@  static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
 	 */
 	dmacr = uap->dmacr;
 	uap->dmacr &= ~UART011_TXDMAE;
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 
-	if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) {
+	if (readw(uap->port.membase + uap->fr) & UART01x_FR_TXFF) {
 		/*
 		 * No space in the FIFO, so enable the transmit interrupt
 		 * so we know when there is space.  Note that once we've
@@ -695,13 +770,13 @@  static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
 		return false;
 	}
 
-	writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+	writew(uap->port.x_char, uap->port.membase + uap->dr);
 	uap->port.icount.tx++;
 	uap->port.x_char = 0;
 
 	/* Success - restore the DMA state */
 	uap->dmacr = dmacr;
-	writew(dmacr, uap->port.membase + UART011_DMACR);
+	writew(dmacr, uap->port.membase + uap->u1_dmacr);
 
 	return true;
 }
@@ -729,7 +804,7 @@  __acquires(&uap->port.lock)
 			     DMA_TO_DEVICE);
 		uap->dmatx.queued = false;
 		uap->dmacr &= ~UART011_TXDMAE;
-		writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+		writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 	}
 }
 
@@ -769,11 +844,11 @@  static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
 	dma_async_issue_pending(rxchan);
 
 	uap->dmacr |= UART011_RXDMAE;
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 	uap->dmarx.running = true;
 
 	uap->im &= ~UART011_RXIM;
-	writew(uap->im, uap->port.membase + UART011_IMSC);
+	writew(uap->im, uap->port.membase + uap->u1_imsc);
 
 	return 0;
 }
@@ -832,7 +907,7 @@  static void pl011_dma_rx_chars(struct uart_amba_port *uap,
 	if (dma_count == pending && readfifo) {
 		/* Clear any error flags */
 		writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
-		       uap->port.membase + UART011_ICR);
+		       uap->port.membase + uap->u1_icr);
 
 		/*
 		 * If we read all the DMA'd characters, and we had an
@@ -880,7 +955,7 @@  static void pl011_dma_rx_irq(struct uart_amba_port *uap)
 
 	/* Disable RX DMA - incoming data will wait in the FIFO */
 	uap->dmacr &= ~UART011_RXDMAE;
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 	uap->dmarx.running = false;
 
 	pending = sgbuf->sg.length - state.residue;
@@ -900,7 +975,7 @@  static void pl011_dma_rx_irq(struct uart_amba_port *uap)
 		dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
 			"fall back to interrupt mode\n");
 		uap->im |= UART011_RXIM;
-		writew(uap->im, uap->port.membase + UART011_IMSC);
+		writew(uap->im, uap->port.membase + uap->u1_imsc);
 	}
 }
 
@@ -948,7 +1023,7 @@  static void pl011_dma_rx_callback(void *data)
 		dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
 			"fall back to interrupt mode\n");
 		uap->im |= UART011_RXIM;
-		writew(uap->im, uap->port.membase + UART011_IMSC);
+		writew(uap->im, uap->port.membase + uap->u1_imsc);
 	}
 }
 
@@ -961,7 +1036,7 @@  static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
 {
 	/* FIXME.  Just disable the DMA enable */
 	uap->dmacr &= ~UART011_RXDMAE;
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 }
 
 /*
@@ -1005,7 +1080,7 @@  static void pl011_dma_rx_poll(unsigned long args)
 		spin_lock_irqsave(&uap->port.lock, flags);
 		pl011_dma_rx_stop(uap);
 		uap->im |= UART011_RXIM;
-		writew(uap->im, uap->port.membase + UART011_IMSC);
+		writew(uap->im, uap->port.membase + uap->u1_imsc);
 		spin_unlock_irqrestore(&uap->port.lock, flags);
 
 		uap->dmarx.running = false;
@@ -1064,7 +1139,7 @@  static void pl011_dma_startup(struct uart_amba_port *uap)
 skip_rx:
 	/* Turn on DMA error (RX/TX will be enabled on demand) */
 	uap->dmacr |= UART011_DMAONERR;
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 
 	/*
 	 * ST Micro variants has some specific dma burst threshold
@@ -1098,12 +1173,12 @@  static void pl011_dma_shutdown(struct uart_amba_port *uap)
 		return;
 
 	/* Disable RX and TX DMA */
-	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+	while (readw(uap->port.membase + uap->fr) & uap->fr_busy)
 		barrier();
 
 	spin_lock_irq(&uap->port.lock);
 	uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
-	writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+	writew(uap->dmacr, uap->port.membase + uap->u1_dmacr);
 	spin_unlock_irq(&uap->port.lock);
 
 	if (uap->using_tx_dma) {
@@ -1204,7 +1279,7 @@  static void pl011_stop_tx(struct uart_port *port)
 	    container_of(port, struct uart_amba_port, port);
 
 	uap->im &= ~UART011_TXIM;
-	writew(uap->im, uap->port.membase + UART011_IMSC);
+	writew(uap->im, uap->port.membase + uap->u1_imsc);
 	pl011_dma_tx_stop(uap);
 }
 
@@ -1215,7 +1290,7 @@  static void pl011_start_tx(struct uart_port *port)
 
 	if (!pl011_dma_tx_start(uap)) {
 		uap->im |= UART011_TXIM;
-		writew(uap->im, uap->port.membase + UART011_IMSC);
+		writew(uap->im, uap->port.membase + uap->u1_imsc);
 	}
 }
 
@@ -1226,7 +1301,7 @@  static void pl011_stop_rx(struct uart_port *port)
 
 	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
 		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
-	writew(uap->im, uap->port.membase + UART011_IMSC);
+	writew(uap->im, uap->port.membase + uap->u1_imsc);
 
 	pl011_dma_rx_stop(uap);
 }
@@ -1237,7 +1312,7 @@  static void pl011_enable_ms(struct uart_port *port)
 	    container_of(port, struct uart_amba_port, port);
 
 	uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
-	writew(uap->im, uap->port.membase + UART011_IMSC);
+	writew(uap->im, uap->port.membase + uap->u1_imsc);
 }
 
 static void pl011_rx_chars(struct uart_amba_port *uap)
@@ -1257,7 +1332,7 @@  __acquires(&uap->port.lock)
 			dev_dbg(uap->port.dev, "could not trigger RX DMA job "
 				"fall back to interrupt mode again\n");
 			uap->im |= UART011_RXIM;
-			writew(uap->im, uap->port.membase + UART011_IMSC);
+			writew(uap->im, uap->port.membase + uap->u1_imsc);
 		} else {
 #ifdef CONFIG_DMA_ENGINE
 			/* Start Rx DMA poll */
@@ -1280,7 +1355,7 @@  static void pl011_tx_chars(struct uart_amba_port *uap)
 	int count;
 
 	if (uap->port.x_char) {
-		writew(uap->port.x_char, uap->port.membase + UART01x_DR);
+		writew(uap->port.x_char, uap->port.membase + uap->dr);
 		uap->port.icount.tx++;
 		uap->port.x_char = 0;
 		return;
@@ -1296,7 +1371,7 @@  static void pl011_tx_chars(struct uart_amba_port *uap)
 
 	count = uap->fifosize >> 1;
 	do {
-		writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
+		writew(xmit->buf[xmit->tail], uap->port.membase + uap->dr);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		uap->port.icount.tx++;
 		if (uart_circ_empty(xmit))
@@ -1314,7 +1389,7 @@  static void pl011_modem_status(struct uart_amba_port *uap)
 {
 	unsigned int status, delta;
 
-	status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+	status = readw(uap->port.membase + uap->fr) & UART01x_FR_MODEM_ANY;
 
 	delta = status ^ uap->old_status;
 	uap->old_status = status;
@@ -1325,11 +1400,11 @@  static void pl011_modem_status(struct uart_amba_port *uap)
 	if (delta & UART01x_FR_DCD)
 		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
 
-	if (delta & UART01x_FR_DSR)
+	if (delta & uap->fr_dsr)
 		uap->port.icount.dsr++;
 
-	if (delta & UART01x_FR_CTS)
-		uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
+	if (delta & uap->fr_cts)
+		uart_handle_cts_change(&uap->port, status & uap->fr_cts);
 
 	wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
 }
@@ -1343,25 +1418,27 @@  static irqreturn_t pl011_int(int irq, void *dev_id)
 	unsigned int dummy_read;
 
 	spin_lock_irqsave(&uap->port.lock, flags);
-	status = readw(uap->port.membase + UART011_MIS);
+	status = readw(uap->port.membase + uap->u1_mis);
 	if (status) {
 		do {
 			if (uap->vendor->cts_event_workaround) {
 				/* workaround to make sure that all bits are unlocked.. */
-				writew(0x00, uap->port.membase + UART011_ICR);
+				writew(0x00, uap->port.membase + uap->u1_icr);
 
 				/*
 				 * WA: introduce 26ns(1 uart clk) delay before W1C;
 				 * single apb access will incur 2 pclk(133.12Mhz) delay,
 				 * so add 2 dummy reads
 				 */
-				dummy_read = readw(uap->port.membase + UART011_ICR);
-				dummy_read = readw(uap->port.membase + UART011_ICR);
+				dummy_read = readw(uap->port.membase
+						   + uap->u1_icr);
+				dummy_read = readw(uap->port.membase
+						   + uap->u1_icr);
 			}
 
 			writew(status & ~(UART011_TXIS|UART011_RTIS|
 					  UART011_RXIS),
-			       uap->port.membase + UART011_ICR);
+			       uap->port.membase + uap->u1_icr);
 
 			if (status & (UART011_RTIS|UART011_RXIS)) {
 				if (pl011_dma_rx_running(uap))
@@ -1378,7 +1455,7 @@  static irqreturn_t pl011_int(int irq, void *dev_id)
 			if (pass_counter-- == 0)
 				break;
 
-			status = readw(uap->port.membase + UART011_MIS);
+			status = readw(uap->port.membase + uap->u1_mis);
 		} while (status != 0);
 		handled = 1;
 	}
@@ -1392,8 +1469,9 @@  static unsigned int pl011_tx_empty(struct uart_port *port)
 {
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
-	unsigned int status = readw(uap->port.membase + UART01x_FR);
-	return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
+	unsigned int status = readw(uap->port.membase + uap->fr);
+
+	return status & (uap->fr_busy|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int pl011_get_mctrl(struct uart_port *port)
@@ -1401,16 +1479,16 @@  static unsigned int pl011_get_mctrl(struct uart_port *port)
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
 	unsigned int result = 0;
-	unsigned int status = readw(uap->port.membase + UART01x_FR);
+	unsigned int status = readw(uap->port.membase + uap->fr);
 
 #define TIOCMBIT(uartbit, tiocmbit)	\
 	if (status & uartbit)		\
 		result |= tiocmbit
 
 	TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
-	TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
-	TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
-	TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
+	TIOCMBIT(uap->fr_dsr, TIOCM_DSR);
+	TIOCMBIT(uap->fr_cts, TIOCM_CTS);
+	TIOCMBIT(uap->u1_fr_ri, TIOCM_RNG);
 #undef TIOCMBIT
 	return result;
 }
@@ -1421,7 +1499,7 @@  static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 	    container_of(port, struct uart_amba_port, port);
 	unsigned int cr;
 
-	cr = readw(uap->port.membase + UART011_CR);
+	cr = readw(uap->port.membase + uap->u1_cr);
 
 #define	TIOCMBIT(tiocmbit, uartbit)		\
 	if (mctrl & tiocmbit)		\
@@ -1441,7 +1519,7 @@  static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 	}
 #undef TIOCMBIT
 
-	writew(cr, uap->port.membase + UART011_CR);
+	writew(cr, uap->port.membase + uap->u1_cr);
 }
 
 static void pl011_break_ctl(struct uart_port *port, int break_state)
@@ -1469,7 +1547,7 @@  static void pl011_quiesce_irqs(struct uart_port *port)
 	    container_of(port, struct uart_amba_port, port);
 	unsigned char __iomem *regs = uap->port.membase;
 
-	writew(readw(regs + UART011_MIS), regs + UART011_ICR);
+	writew(readw(regs + uap->u1_mis), regs + uap->u1_icr);
 	/*
 	 * There is no way to clear TXIM as this is "ready to transmit IRQ", so
 	 * we simply mask it. start_tx() will unmask it.
@@ -1483,7 +1561,7 @@  static void pl011_quiesce_irqs(struct uart_port *port)
 	 * (including tx queue), so we're also fine with start_tx()'s caller
 	 * side.
 	 */
-	writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC);
+	writew(readw(regs + uap->u1_imsc) & ~UART011_TXIM, regs + uap->u1_imsc);
 }
 
 static int pl011_get_poll_char(struct uart_port *port)
@@ -1498,11 +1576,11 @@  static int pl011_get_poll_char(struct uart_port *port)
 	 */
 	pl011_quiesce_irqs(port);
 
-	status = readw(uap->port.membase + UART01x_FR);
+	status = readw(uap->port.membase + uap->fr);
 	if (status & UART01x_FR_RXFE)
 		return NO_POLL_CHAR;
 
-	return readw(uap->port.membase + UART01x_DR);
+	return readw(uap->port.membase + uap->dr);
 }
 
 static void pl011_put_poll_char(struct uart_port *port,
@@ -1511,10 +1589,10 @@  static void pl011_put_poll_char(struct uart_port *port,
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
 
-	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+	while (readw(uap->port.membase + uap->fr) & UART01x_FR_TXFF)
 		barrier();
 
-	writew(ch, uap->port.membase + UART01x_DR);
+	writew(ch, uap->port.membase + uap->dr);
 }
 
 #endif /* CONFIG_CONSOLE_POLL */
@@ -1539,14 +1617,14 @@  static int pl011_hwinit(struct uart_port *port)
 
 	/* Clear pending error and receive interrupts */
 	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
-	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + uap->u1_icr);
 
 	/*
 	 * Save interrupts enable mask, and enable RX interrupts in case if
 	 * the interrupt is used for NMI entry.
 	 */
-	uap->im = readw(uap->port.membase + UART011_IMSC);
-	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
+	uap->im = readw(uap->port.membase + uap->u1_imsc);
+	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + uap->u1_imsc);
 
 	if (dev_get_platdata(uap->port.dev)) {
 		struct amba_pl011_data *plat;
@@ -1568,7 +1646,7 @@  static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
 		 * to get this delay write read only register 10 times
 		 */
 		for (i = 0; i < 10; ++i)
-			writew(0xff, uap->port.membase + UART011_MIS);
+			writew(0xff, uap->port.membase + uap->u1_mis);
 		writew(lcr_h, uap->port.membase + uap->lcrh_tx);
 	}
 }
@@ -1584,7 +1662,7 @@  static int pl011_startup(struct uart_port *port)
 	if (retval)
 		goto clk_dis;
 
-	writew(uap->im, uap->port.membase + UART011_IMSC);
+	writew(uap->im, uap->port.membase + uap->u1_imsc);
 
 	/*
 	 * Allocate the IRQ
@@ -1593,7 +1671,7 @@  static int pl011_startup(struct uart_port *port)
 	if (retval)
 		goto clk_dis;
 
-	writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
+	writew(uap->vendor->ifls, uap->port.membase + uap->u1_ifls);
 
 	/*
 	 * Provoke TX FIFO interrupt into asserting. Taking care to preserve
@@ -1607,12 +1685,12 @@  static int pl011_startup(struct uart_port *port)
 	lcr_h = readw(uap->port.membase + uap->lcrh_rx);
 
 	cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
-	writew(cr, uap->port.membase + UART011_CR);
+	writew(cr, uap->port.membase + uap->u1_cr);
 	writew(0, uap->port.membase + UART011_FBRD);
 	writew(1, uap->port.membase + UART011_IBRD);
 	pl011_write_lcr_h(uap, 0);
-	writew(0, uap->port.membase + UART01x_DR);
-	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
+	writew(0, uap->port.membase + uap->dr);
+	while (readw(uap->port.membase + uap->fr) & uap->fr_busy)
 		barrier();
 
 	writew(fbrd, uap->port.membase + UART011_FBRD);
@@ -1622,14 +1700,15 @@  static int pl011_startup(struct uart_port *port)
 	/* restore RTS and DTR */
 	cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
 	cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
-	writew(cr, uap->port.membase + UART011_CR);
+	writew(cr, uap->port.membase + uap->u1_cr);
 
 	spin_unlock_irq(&uap->port.lock);
 
 	/*
 	 * initialise the old status of the modem signals
 	 */
-	uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+	uap->old_status = readw(uap->port.membase + uap->fr)
+			  & UART01x_FR_MODEM_ANY;
 
 	/* Startup DMA */
 	pl011_dma_startup(uap);
@@ -1642,11 +1721,11 @@  static int pl011_startup(struct uart_port *port)
 	spin_lock_irq(&uap->port.lock);
 	/* Clear out any spuriously appearing RX interrupts */
 	 writew(UART011_RTIS | UART011_RXIS,
-		uap->port.membase + UART011_ICR);
+		uap->port.membase + uap->u1_icr);
 	uap->im = UART011_RTIM;
 	if (!pl011_dma_rx_running(uap))
 		uap->im |= UART011_RXIM;
-	writew(uap->im, uap->port.membase + UART011_IMSC);
+	writew(uap->im, uap->port.membase + uap->u1_imsc);
 	spin_unlock_irq(&uap->port.lock);
 
 	return 0;
@@ -1677,8 +1756,8 @@  static void pl011_shutdown(struct uart_port *port)
 	 */
 	spin_lock_irq(&uap->port.lock);
 	uap->im = 0;
-	writew(uap->im, uap->port.membase + UART011_IMSC);
-	writew(0xffff, uap->port.membase + UART011_ICR);
+	writew(uap->im, uap->port.membase + uap->u1_imsc);
+	writew(0xffff, uap->port.membase + uap->u1_icr);
 	spin_unlock_irq(&uap->port.lock);
 
 	pl011_dma_shutdown(uap);
@@ -1696,11 +1775,11 @@  static void pl011_shutdown(struct uart_port *port)
 	 */
 	uap->autorts = false;
 	spin_lock_irq(&uap->port.lock);
-	cr = readw(uap->port.membase + UART011_CR);
+	cr = readw(uap->port.membase + uap->u1_cr);
 	uap->old_cr = cr;
 	cr &= UART011_CR_RTS | UART011_CR_DTR;
 	cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
-	writew(cr, uap->port.membase + UART011_CR);
+	writew(cr, uap->port.membase + uap->u1_cr);
 	spin_unlock_irq(&uap->port.lock);
 
 	/*
@@ -1825,8 +1904,8 @@  pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 		pl011_enable_ms(port);
 
 	/* first, disable everything */
-	old_cr = readw(port->membase + UART011_CR);
-	writew(0, port->membase + UART011_CR);
+	old_cr = readw(port->membase + uap->u1_cr);
+	writew(0, port->membase + uap->u1_cr);
 
 	if (termios->c_cflag & CRTSCTS) {
 		if (old_cr & UART011_CR_RTS)
@@ -1869,7 +1948,7 @@  pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 	 * ----------^----------^----------^----------^-----
 	 */
 	pl011_write_lcr_h(uap, lcr_h);
-	writew(old_cr, port->membase + UART011_CR);
+	writew(old_cr, port->membase + uap->u1_cr);
 
 	spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -1958,9 +2037,9 @@  static void pl011_console_putchar(struct uart_port *port, int ch)
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
 
-	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+	while (readw(uap->port.membase + uap->fr) & UART01x_FR_TXFF)
 		barrier();
-	writew(ch, uap->port.membase + UART01x_DR);
+	writew(ch, uap->port.membase + uap->dr);
 }
 
 static void
@@ -1984,10 +2063,10 @@  pl011_console_write(struct console *co, const char *s, unsigned int count)
 	/*
 	 *	First save the CR then disable the interrupts
 	 */
-	old_cr = readw(uap->port.membase + UART011_CR);
+	old_cr = readw(uap->port.membase + uap->u1_cr);
 	new_cr = old_cr & ~UART011_CR_CTSEN;
 	new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
-	writew(new_cr, uap->port.membase + UART011_CR);
+	writew(new_cr, uap->port.membase + uap->u1_cr);
 
 	uart_console_write(&uap->port, s, count, pl011_console_putchar);
 
@@ -1996,9 +2075,9 @@  pl011_console_write(struct console *co, const char *s, unsigned int count)
 	 *	and restore the TCR
 	 */
 	do {
-		status = readw(uap->port.membase + UART01x_FR);
-	} while (status & UART01x_FR_BUSY);
-	writew(old_cr, uap->port.membase + UART011_CR);
+		status = readw(uap->port.membase + uap->fr);
+	} while (status & uap->fr_busy);
+	writew(old_cr, uap->port.membase + uap->u1_cr);
 
 	if (locked)
 		spin_unlock(&uap->port.lock);
@@ -2011,7 +2090,7 @@  static void __init
 pl011_console_get_options(struct uart_amba_port *uap, int *baud,
 			     int *parity, int *bits)
 {
-	if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
+	if (readw(uap->port.membase + uap->u1_cr) & UART01x_CR_UARTEN) {
 		unsigned int lcr_h, ibrd, fbrd;
 
 		lcr_h = readw(uap->port.membase + uap->lcrh_tx);
@@ -2035,7 +2114,7 @@  pl011_console_get_options(struct uart_amba_port *uap, int *baud,
 		*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
 
 		if (uap->vendor->oversampling) {
-			if (readw(uap->port.membase + UART011_CR)
+			if (readw(uap->port.membase + uap->u1_cr)
 				  & ST_UART011_CR_OVSFACT)
 				*baud *= 2;
 		}
@@ -2102,10 +2181,13 @@  static struct console amba_console = {
 
 static void pl011_putc(struct uart_port *port, int c)
 {
-	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
+
+	while (readl(port->membase + uap->fr) & UART01x_FR_TXFF)
 		;
-	writeb(c, port->membase + UART01x_DR);
-	while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
+	writeb(c, port->membase + uap->dr);
+	while (readl(port->membase + uap->fr) & uap->fr_busy)
 		;
 }
 
@@ -2207,6 +2289,18 @@  static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 	uap->vendor = vendor;
 	uap->lcrh_rx = vendor->lcrh_rx;
 	uap->lcrh_tx = vendor->lcrh_tx;
+	uap->dr = vendor->dr;
+	uap->fr =  vendor->fr;
+	uap->u1_cr = vendor->u1_cr;
+	uap->u1_ifls = vendor->u1_ifls;
+	uap->u1_imsc = vendor->u1_imsc;
+	uap->u1_mis = vendor->u1_mis;
+	uap->u1_icr = vendor->u1_icr;
+	uap->u1_dmacr = vendor->u1_dmacr;
+	uap->fr_busy = vendor->fr_busy;
+	uap->fr_dsr = vendor->fr_dsr;
+	uap->fr_cts = vendor->fr_cts;
+	uap->u1_fr_ri = vendor->u1_fr_ri;
 	uap->old_cr = 0;
 	uap->fifosize = vendor->get_fifosize(dev);
 	uap->port.dev = &dev->dev;
@@ -2221,8 +2315,8 @@  static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 	pl011_dma_probe(&dev->dev, uap);
 
 	/* Ensure interrupts from this UART are masked and cleared */
-	writew(0, uap->port.membase + UART011_IMSC);
-	writew(0xffff, uap->port.membase + UART011_ICR);
+	writew(0, uap->port.membase + uap->u1_imsc);
+	writew(0xffff, uap->port.membase + uap->u1_icr);
 
 	snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
 
@@ -2268,6 +2362,107 @@  static int pl011_remove(struct amba_device *dev)
 	return 0;
 }
 
+static int zx_uart_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct uart_amba_port *uap;
+	struct vendor_data *vendor = &vendor_zx;
+	struct resource *res;
+	void __iomem *base;
+	int i, ret;
+
+	uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
+			   GFP_KERNEL);
+	if (uap == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	i = of_alias_get_id(np, "serial");
+	if (i < 0) {
+		dev_err(&pdev->dev, "failed to get alias id: %d\n", i);
+		ret = i;
+		goto out;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	uap->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(uap->clk)) {
+		ret = PTR_ERR(uap->clk);
+		goto out;
+	}
+
+	uap->vendor = vendor;
+	uap->lcrh_rx = vendor->lcrh_rx;
+	uap->lcrh_tx = vendor->lcrh_tx;
+	uap->dr = vendor->dr;
+	uap->fr =  vendor->fr;
+	uap->u1_cr = vendor->u1_cr;
+	uap->u1_ifls = vendor->u1_ifls;
+	uap->u1_imsc = vendor->u1_imsc;
+	uap->u1_mis = vendor->u1_mis;
+	uap->u1_icr = vendor->u1_icr;
+	uap->u1_dmacr = vendor->u1_dmacr;
+	uap->fr_busy = vendor->fr_busy;
+	uap->fr_dsr = vendor->fr_dsr;
+	uap->fr_cts = vendor->fr_cts;
+	uap->u1_fr_ri = vendor->u1_fr_ri;
+	uap->old_cr = 0;
+	uap->fifosize = 16;
+	uap->port.dev = &pdev->dev;
+	uap->port.mapbase = res->start;
+	uap->port.membase = base;
+	uap->port.iotype = UPIO_MEM;
+	uap->port.irq = platform_get_irq(pdev, 0);
+	uap->port.fifosize = uap->fifosize;
+	uap->port.ops = &amba_pl011_pops;
+	uap->port.flags = UPF_BOOT_AUTOCONF;
+	uap->port.line = i;
+	uap->port.uartclk = clk_get_rate(uap->clk);
+	pl011_dma_probe(&pdev->dev, uap);
+
+	/* Ensure interrupts from this UART are masked and cleared */
+	writew(0, uap->port.membase + uap->u1_imsc);
+	writew(0xffff, uap->port.membase + uap->u1_icr);
+
+	amba_ports[i] = uap;
+
+	platform_set_drvdata(pdev, uap);
+	ret = uart_register_driver(&amba_reg);
+	if (ret < 0) {
+		pr_err("Failed to register AMBA-PL011 driver\n");
+		return ret;
+	}
+	ret = uart_add_one_port(&amba_reg, &uap->port);
+	if (ret) {
+		amba_ports[i] = NULL;
+		pl011_dma_remove(uap);
+	}
+ out:
+	return ret;
+}
+
+static int zx_uart_remove(struct platform_device *pdev)
+{
+	struct uart_amba_port *uap = platform_get_drvdata(pdev);
+	int i;
+
+	uart_remove_one_port(&amba_reg, &uap->port);
+
+	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
+		if (amba_ports[i] == uap)
+			amba_ports[i] = NULL;
+
+	pl011_dma_remove(uap);
+	return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int pl011_suspend(struct device *dev)
 {
@@ -2308,6 +2503,7 @@  static struct amba_id pl011_ids[] = {
 
 MODULE_DEVICE_TABLE(amba, pl011_ids);
 
+#ifdef CONFIG_ARM_AMBA
 static struct amba_driver pl011_driver = {
 	.drv = {
 		.name	= "uart-pl011",
@@ -2317,17 +2513,49 @@  static struct amba_driver pl011_driver = {
 	.probe		= pl011_probe,
 	.remove		= pl011_remove,
 };
+#endif
+
+#ifdef CONFIG_SOC_ZX296702
+static const struct of_device_id zx_uart_dt_ids[] = {
+	{ .compatible = "zte,zx296702-uart", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, zx_uart_dt_ids);
+
+static struct platform_driver zx_uart_driver = {
+	.driver = {
+		.name	= "zx-uart",
+		.owner	= THIS_MODULE,
+		.pm	= &pl011_dev_pm_ops,
+		.of_match_table = zx_uart_dt_ids,
+	},
+	.probe		= zx_uart_probe,
+	.remove		= zx_uart_remove,
+};
+#endif
 
 static int __init pl011_init(void)
 {
 	printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
 
+#ifdef CONFIG_ARM_AMBA
+
 	return amba_driver_register(&pl011_driver);
+#endif
+
+#ifdef CONFIG_SOC_ZX296702
+	return platform_driver_register(&zx_uart_driver);
+#endif
 }
 
 static void __exit pl011_exit(void)
 {
+#ifdef CONFIG_ARM_AMBA
 	amba_driver_unregister(&pl011_driver);
+#endif
+#ifdef CONFIG_SOC_ZX296702
+	platform_driver_unregister(&zx_uart_driver);
+#endif
 }
 
 /*
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 0ddb5c0..b077859 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -31,6 +31,7 @@ 
  *  UART Register Offsets.
  */
 #define UART01x_DR		0x00	/* Data read or written from the interface. */
+#define ZX_UART01x_DR		0x04	/* Data read or written from the interface. */
 #define UART01x_RSR		0x04	/* Receive status register (Read). */
 #define UART01x_ECR		0x04	/* Error clear register (Write). */
 #define UART010_LCRH		0x08	/* Line control register, high byte. */
@@ -39,6 +40,7 @@ 
 #define ST_UART011_TIMEOUT	0x0C    /* Timeout period register. */
 #define UART010_LCRL		0x10	/* Line control register, low byte. */
 #define UART010_CR		0x14	/* Control register. */
+#define ZX_UART01x_FR		0x14	/* Flag register (Read only). */
 #define UART01x_FR		0x18	/* Flag register (Read only). */
 #define UART010_IIR		0x1C	/* Interrupt identification register (Read). */
 #define UART010_ICR		0x1C	/* Interrupt clear register (Write). */
@@ -48,14 +50,22 @@ 
 #define UART011_FBRD		0x28	/* Fractional baud rate divisor register. */
 #define UART011_LCRH		0x2c	/* Line control register. */
 #define ST_UART011_LCRH_TX	0x2c    /* Tx Line control register. */
+#define ZX_UART011_LCRH_TX	0x30    /* Tx Line control register. */
 #define UART011_CR		0x30	/* Control register. */
 #define UART011_IFLS		0x34	/* Interrupt fifo level select. */
+#define ZX_UART011_CR		0x34	/* Control register. */
+#define ZX_UART011_IFLS		0x38	/* Interrupt fifo level select. */
 #define UART011_IMSC		0x38	/* Interrupt mask. */
 #define UART011_RIS		0x3c	/* Raw interrupt status. */
+#define ZX_UART011_IMSC		0x40	/* Interrupt mask. */
 #define UART011_MIS		0x40	/* Masked interrupt status. */
+#define ZX_UART011_RIS		0x44	/* Raw interrupt status. */
 #define UART011_ICR		0x44	/* Interrupt clear register. */
 #define UART011_DMACR		0x48	/* DMA control register. */
+#define ZX_UART011_MIS		0x48	/* Masked interrupt status. */
+#define ZX_UART011_ICR		0x4c	/* Interrupt clear register. */
 #define ST_UART011_XFCR		0x50	/* XON/XOFF control register. */
+#define ZX_UART011_DMACR	0x50	/* DMA control register. */
 #define ST_UART011_XON1		0x54	/* XON1 register. */
 #define ST_UART011_XON2		0x58	/* XON2 register. */
 #define ST_UART011_XOFF1	0x5C	/* XON1 register. */
@@ -75,15 +85,21 @@ 
 #define UART01x_RSR_PE 		0x02
 #define UART01x_RSR_FE 		0x01
 
+#define UART011_FR_TXBUSY       0x100
+#define UART011_FR_RXBUSY       0x200
+#define ZX_UART01x_FR_BUSY         (UART011_FR_RXBUSY | UART011_FR_TXBUSY)
 #define UART011_FR_RI		0x100
 #define UART011_FR_TXFE		0x080
 #define UART011_FR_RXFF		0x040
 #define UART01x_FR_TXFF		0x020
 #define UART01x_FR_RXFE		0x010
 #define UART01x_FR_BUSY		0x008
+#define ZX_UART01x_FR_DSR       0x008
 #define UART01x_FR_DCD 		0x004
 #define UART01x_FR_DSR 		0x002
+#define ZX_UART01x_FR_CTS          0x002
 #define UART01x_FR_CTS 		0x001
+#define ZX_UART011_FR_RI           0x001
 #define UART01x_FR_TMSK		(UART01x_FR_TXFF + UART01x_FR_BUSY)
 
 #define UART011_CR_CTSEN	0x8000	/* CTS hardware flow control */