Commit 909102db authored by Barry Song's avatar Barry Song Committed by Greg Kroah-Hartman

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: default avatarBarry Song <Baohua.Song@csr.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f7d2c0bb
...@@ -139,40 +139,66 @@ static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) ...@@ -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) static void sirfsoc_uart_stop_tx(struct uart_port *port)
{ {
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned int regv; unsigned int regv;
if (!sirfport->is_marco) {
regv = rd_regl(port, SIRFUART_INT_EN); regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_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) void sirfsoc_uart_start_tx(struct uart_port *port)
{ {
struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long regv; unsigned long regv;
sirfsoc_uart_pio_tx_chars(sirfport, 1); sirfsoc_uart_pio_tx_chars(sirfport, 1);
wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START); wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START);
if (!sirfport->is_marco) {
regv = rd_regl(port, SIRFUART_INT_EN); regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_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) static void sirfsoc_uart_stop_rx(struct uart_port *port)
{ {
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long regv; unsigned long regv;
wr_regl(port, SIRFUART_RX_FIFO_OP, 0); wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
if (!sirfport->is_marco) {
regv = rd_regl(port, SIRFUART_INT_EN); regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_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) static void sirfsoc_uart_disable_ms(struct uart_port *port)
{ {
struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long reg; unsigned long reg;
sirfport->ms_enabled = 0; sirfport->ms_enabled = 0;
if (!sirfport->hw_flow_ctrl) if (!sirfport->hw_flow_ctrl)
return; return;
reg = rd_regl(port, SIRFUART_AFC_CTRL); reg = rd_regl(port, SIRFUART_AFC_CTRL);
wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF); wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF);
if (!sirfport->is_marco) {
reg = rd_regl(port, SIRFUART_INT_EN); reg = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_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) static void sirfsoc_uart_enable_ms(struct uart_port *port)
...@@ -180,13 +206,20 @@ 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); struct sirfsoc_uart_port *sirfport = to_sirfport(port);
unsigned long reg; unsigned long reg;
unsigned long flg; unsigned long flg;
if (!sirfport->hw_flow_ctrl) if (!sirfport->hw_flow_ctrl)
return; return;
flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN; flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN;
reg = rd_regl(port, SIRFUART_AFC_CTRL); reg = rd_regl(port, SIRFUART_AFC_CTRL);
wr_regl(port, SIRFUART_AFC_CTRL, reg | flg); wr_regl(port, SIRFUART_AFC_CTRL, reg | flg);
if (!sirfport->is_marco) {
reg = rd_regl(port, SIRFUART_INT_EN); reg = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_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, uart_handle_cts_change(port,
!(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS)); !(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS));
sirfport->ms_enabled = 1; sirfport->ms_enabled = 1;
...@@ -313,9 +346,16 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) ...@@ -313,9 +346,16 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
static void sirfsoc_uart_start_rx(struct uart_port *port) static void sirfsoc_uart_start_rx(struct uart_port *port)
{ {
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
if (!sirfport->is_marco) {
unsigned long regv; unsigned long regv;
regv = rd_regl(port, SIRFUART_INT_EN); regv = rd_regl(port, SIRFUART_INT_EN);
wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_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, SIRFUART_RX_FIFO_RESET);
wr_regl(port, SIRFUART_RX_FIFO_OP, 0); wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START); wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
...@@ -513,7 +553,12 @@ static int sirfsoc_uart_startup(struct uart_port *port) ...@@ -513,7 +553,12 @@ static int sirfsoc_uart_startup(struct uart_port *port)
static void sirfsoc_uart_shutdown(struct uart_port *port) static void sirfsoc_uart_shutdown(struct uart_port *port)
{ {
struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_uart_port *sirfport = to_sirfport(port);
if (!sirfport->is_marco)
wr_regl(port, SIRFUART_INT_EN, 0); wr_regl(port, SIRFUART_INT_EN, 0);
else
wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
free_irq(port->irq, sirfport); free_irq(port->irq, sirfport);
if (sirfport->ms_enabled) { if (sirfport->ms_enabled) {
sirfsoc_uart_disable_ms(port); sirfsoc_uart_disable_ms(port);
...@@ -652,6 +697,9 @@ int sirfsoc_uart_probe(struct platform_device *pdev) ...@@ -652,6 +697,9 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
port->dev = &pdev->dev; port->dev = &pdev->dev;
port->private_data = sirfport; 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)) if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
sirfport->hw_flow_ctrl = 1; sirfport->hw_flow_ctrl = 1;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define SIRFUART_DIVISOR 0x0050 #define SIRFUART_DIVISOR 0x0050
#define SIRFUART_INT_EN 0x0054 #define SIRFUART_INT_EN 0x0054
#define SIRFUART_INT_STATUS 0x0058 #define SIRFUART_INT_STATUS 0x0058
#define SIRFUART_INT_EN_CLR 0x0060
#define SIRFUART_TX_DMA_IO_CTRL 0x0100 #define SIRFUART_TX_DMA_IO_CTRL 0x0100
#define SIRFUART_TX_DMA_IO_LEN 0x0104 #define SIRFUART_TX_DMA_IO_LEN 0x0104
#define SIRFUART_TX_FIFO_CTRL 0x0108 #define SIRFUART_TX_FIFO_CTRL 0x0108
...@@ -164,6 +165,8 @@ struct sirfsoc_uart_port { ...@@ -164,6 +165,8 @@ struct sirfsoc_uart_port {
struct uart_port port; struct uart_port port;
struct pinctrl *p; struct pinctrl *p;
struct clk *clk; struct clk *clk;
/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
bool is_marco;
}; };
/* Hardware Flow Control */ /* Hardware Flow Control */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment