Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+62 −14
Original line number Diff line number Diff line
@@ -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;

	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);

	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);

	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);

	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);

	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 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)

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;
		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 @@ static int sirfsoc_uart_startup(struct uart_port *port)
static void sirfsoc_uart_shutdown(struct uart_port *port)
{
	struct sirfsoc_uart_port *sirfport = to_sirfport(port);

	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;

+3 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#define SIRFUART_DIVISOR			0x0050
#define SIRFUART_INT_EN				0x0054
#define SIRFUART_INT_STATUS			0x0058
#define SIRFUART_INT_EN_CLR			0x0060
#define SIRFUART_TX_DMA_IO_CTRL			0x0100
#define SIRFUART_TX_DMA_IO_LEN			0x0104
#define SIRFUART_TX_FIFO_CTRL			0x0108
@@ -164,6 +165,8 @@ struct sirfsoc_uart_port {
	struct uart_port		port;
	struct pinctrl			*p;
	struct clk			*clk;
	/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
	bool				is_marco;
};

/* Hardware Flow Control */