summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/sirfsoc_uart.c
diff options
context:
space:
mode:
authorBarry Song <Baohua.Song@csr.com>2013-08-07 13:35:38 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-12 11:29:53 -0700
commit909102db44faf40bae96d8f9d23de79e1ca0853a (patch)
treebb42958f670ab18e859a25dd2b1e5a3c48086527 /drivers/tty/serial/sirfsoc_uart.c
parentf7d2c0bbdb7b784cc035cacb7d36b379ba1c3bef (diff)
serial: sirf: add support for Marco chip
the marco and coming new CSR multiple SoCs have SET/CLR pair for INTEN registers to avoid some read-modify-write. this patch adds support for this and make the driver support current up and coming mp SoCs. Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/sirfsoc_uart.c')
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c76
1 files changed, 62 insertions, 14 deletions
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 67a0d1b8341c..26a3bc834fea 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -139,40 +139,66 @@ static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void sirfsoc_uart_stop_tx(struct uart_port *port)
{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned int regv;
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
+
+ if (!sirfport->is_marco) {
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
+ } else {
+ wr_regl(port, SIRFUART_INT_EN_CLR, SIRFUART_TX_INT_EN);
+ }
}
void sirfsoc_uart_start_tx(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long regv;
+
sirfsoc_uart_pio_tx_chars(sirfport, 1);
wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START);
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_INT_EN);
+
+ if (!sirfport->is_marco) {
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_INT_EN);
+ } else {
+ wr_regl(port, SIRFUART_INT_EN, SIRFUART_TX_INT_EN);
+ }
}
static void sirfsoc_uart_stop_rx(struct uart_port *port)
{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long regv;
+
wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_INT_EN);
+
+ if (!sirfport->is_marco) {
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_INT_EN);
+ } else {
+ wr_regl(port, SIRFUART_INT_EN_CLR, SIRFUART_RX_IO_INT_EN);
+ }
}
static void sirfsoc_uart_disable_ms(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long reg;
+
sirfport->ms_enabled = 0;
if (!sirfport->hw_flow_ctrl)
return;
+
reg = rd_regl(port, SIRFUART_AFC_CTRL);
wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF);
- reg = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_INT_EN);
+
+ if (!sirfport->is_marco) {
+ reg = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_INT_EN);
+ } else {
+ wr_regl(port, SIRFUART_INT_EN_CLR, SIRFUART_CTS_INT_EN);
+ }
}
static void sirfsoc_uart_enable_ms(struct uart_port *port)
@@ -180,13 +206,20 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port)
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long reg;
unsigned long flg;
+
if (!sirfport->hw_flow_ctrl)
return;
flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN;
reg = rd_regl(port, SIRFUART_AFC_CTRL);
wr_regl(port, SIRFUART_AFC_CTRL, reg | flg);
- reg = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_INT_EN);
+
+ if (!sirfport->is_marco) {
+ reg = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_INT_EN);
+ } else {
+ wr_regl(port, SIRFUART_INT_EN, SIRFUART_CTS_INT_EN);
+ }
+
uart_handle_cts_change(port,
!(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS));
sirfport->ms_enabled = 1;
@@ -313,9 +346,16 @@ recv_char:
static void sirfsoc_uart_start_rx(struct uart_port *port)
{
- unsigned long regv;
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_INT_EN);
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+
+ if (!sirfport->is_marco) {
+ unsigned long regv;
+ regv = rd_regl(port, SIRFUART_INT_EN);
+ wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_INT_EN);
+ } else {
+ wr_regl(port, SIRFUART_INT_EN, SIRFUART_RX_IO_INT_EN);
+ }
+
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
@@ -513,7 +553,12 @@ irq_err:
static void sirfsoc_uart_shutdown(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- wr_regl(port, SIRFUART_INT_EN, 0);
+
+ if (!sirfport->is_marco)
+ wr_regl(port, SIRFUART_INT_EN, 0);
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
+
free_irq(port->irq, sirfport);
if (sirfport->ms_enabled) {
sirfsoc_uart_disable_ms(port);
@@ -652,6 +697,9 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
port->private_data = sirfport;
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
+ sirfport->is_marco = true;
+
if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
sirfport->hw_flow_ctrl = 1;