aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-06-24 14:46:32 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-06-24 14:46:32 +0200
commitcddd53e8aa4fc442e26a7a7be183593ce31453ca (patch)
tree8da733255cf6d956855af557340ee6274abfdce6 /drivers/tty
parenttty: serial: Add UART driver for Cortina-Access platform (diff)
downloadlinux-dev-cddd53e8aa4fc442e26a7a7be183593ce31453ca.tar.xz
linux-dev-cddd53e8aa4fc442e26a7a7be183593ce31453ca.zip
Revert "tty: serial: Add UART driver for Cortina-Access platform"
This reverts commit b61c8bf4694b5115766849378dcb8787ff54e65e. It never made it to a public mailing list and still needs some work based on the review comments. So revert it for now. Reported-by: Geert Uytterhoeven <geert@linux-m68k.org> Link: https://lore.kernel.org/r/CAMuHMdXA9-ajoAza2JAW5879ECieMm1dbBbKHgJhDa7=3kWu3w@mail.gmail.com Cc: Jason Li <jason.li@cortina-access.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/Kconfig19
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/serial_cortina-access.c798
3 files changed, 0 insertions, 818 deletions
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2fa39cd78c56..24282ad99d85 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1561,25 +1561,6 @@ config SERIAL_LITEUART_CONSOLE
and warnings and which allows logins in single user mode).
Otherwise, say 'N'.
-config SERIAL_CORTINA_ACCESS
- tristate "Cortina-Access serial port support"
- select SERIAL_CORE
- help
- This driver is for Cortina-Access SoC's UART. If you have a machine
- based on the Cortina-Access SoC and wish to use the serial port,
- say 'Y' here. Otherwise, say 'N'.
-
-config SERIAL_CORTINA_ACCESS_CONSOLE
- bool "Console on Cortina-ACCESS serial port"
- depends on SERIAL_CORTINA_ACCESS=y
- select SERIAL_CORE_CONSOLE
- select SERIAL_EARLYCON
- help
- Say 'Y' here if you wish to use Cortina-Access UART as the system
- console. (the system console is the device which receives all kernel
- messages and warnings and which allows logins in single user mode)
- /dev/ttyS* is default device node.
-
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index f3f531a48854..7da0856cd198 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -87,7 +87,6 @@ obj-$(CONFIG_SERIAL_RDA) += rda-uart.o
obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o
-obj-$(CONFIG_SERIAL_CORTINA_ACCESS) += serial_cortina-access.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/serial_cortina-access.c b/drivers/tty/serial/serial_cortina-access.c
deleted file mode 100644
index b4b9362bb4e6..000000000000
--- a/drivers/tty/serial/serial_cortina-access.c
+++ /dev/null
@@ -1,798 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * UART driver for Cortina-Access Soc platform
- * Copyright (C) 2021 Cortina-Access Inc.
- */
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-/***************************************
- * UART Related registers
- ****************************************/
-/* register definitions */
-#define CFG 0x00
-#define FC 0x04
-#define RX_SAMPLE 0x08
-#define RT_TUNE 0x0C
-#define TX_DAT 0x10
-#define RX_DAT 0x14
-#define INFO 0x18
-#define IE 0x1C
-#define INT 0x24
-#define STATUS 0x2C
-
-/* CFG */
-#define CFG_STOP_2BIT BIT(2)
-#define CFG_PARITY_EVEN BIT(3)
-#define CFG_PARITY_EN BIT(4)
-#define CFG_TX_EN BIT(5)
-#define CFG_RX_EN BIT(6)
-#define CFG_UART_EN BIT(7)
-#define CFG_BAUD_SART_SHIFT 8
-
-/* INFO */
-#define INFO_TX_EMPTY BIT(3)
-#define INFO_TX_FULL BIT(2)
-#define INFO_RX_EMPTY BIT(1)
-#define INFO_RX_FULL BIT(0)
-
-/* Interrupt */
-#define RX_BREAK BIT(7)
-#define RX_FIFO_NONEMPTYE BIT(6)
-#define TX_FIFO_EMPTYE BIT(5)
-#define RX_FIFO_UNDERRUNE BIT(4)
-#define RX_FIFO_OVERRUNE BIT(3)
-#define RX_PARITY_ERRE BIT(2)
-#define RX_STOP_ERRE BIT(1)
-#define TX_FIFO_OVERRUNE BIT(0)
-
-#define TX_TIMEOUT 5000
-#define UART_NR 4
-#define CA_UART_NAME_LEN 32
-struct cortina_uart_port {
- struct uart_port uart;
- char name[CA_UART_NAME_LEN];
- char has_bi;
- unsigned int may_wakeup;
-};
-
-static struct cortina_uart_port *cortina_uart_ports;
-
-static irqreturn_t cortina_uart_interrupt(int irq, void *dev_id);
-
-/* Return uart_port pointer base on index */
-struct cortina_uart_port *cortina_uart_get_port(unsigned int index)
-{
- struct cortina_uart_port *pca_port = cortina_uart_ports;
-
- if (index >= UART_NR) {
- /* return 1st element if invalid index */
- index = 0;
- }
-
- pca_port += index;
-
- return pca_port;
-}
-
-/* uart_ops functions */
-static unsigned int cortina_uart_tx_empty(struct uart_port *port)
-{
- /* Return 0 on FIXO condition, TIOCSER_TEMT otherwise */
- return (readl(port->membase + INFO) & INFO_TX_EMPTY) ? TIOCSER_TEMT : 0;
-}
-
-static void cortina_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-/*
- * Even if we do not support configuring the modem control lines, this
- * function must be proided to the serial core.
- * port->ops->set_mctrl() be called in uart_configure_port()
- */
-}
-
-static unsigned int cortina_uart_get_mctrl(struct uart_port *port)
-{
- /* Unimplemented signals asserted, per Documentation/serial/driver */
- return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void cortina_uart_stop_tx(struct uart_port *port)
-{
- /* Turn off Tx interrupts. The port lock is held at this point */
- unsigned int reg_v;
-
- reg_v = readl(port->membase + IE);
- writel(reg_v & ~TX_FIFO_EMPTYE, port->membase + IE);
-}
-
-static inline void cortina_transmit_buffer(struct uart_port *port)
-{
- struct circ_buf *xmit = &port->state->xmit;
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- cortina_uart_stop_tx(port);
- return;
- }
-
- do {
- /* send xmit->buf[xmit->tail] out the port here */
- writel(xmit->buf[xmit->tail], port->membase + TX_DAT);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- if ((readl(port->membase + INFO) & INFO_TX_FULL))
- break;
- } while (!uart_circ_empty(xmit));
-
- if (uart_circ_empty(xmit))
- cortina_uart_stop_tx(port);
-}
-
-static void cortina_uart_start_tx(struct uart_port *port)
-{
- /* Turn on Tx interrupts. The port lock is held at this point */
- unsigned int reg_v;
-
- reg_v = readl(port->membase + IE);
- writel((reg_v | TX_FIFO_EMPTYE), port->membase + IE);
-
- reg_v = readl(port->membase + CFG);
- writel(reg_v | CFG_TX_EN, port->membase + CFG);
-
- if (readl(port->membase + INFO) & INFO_TX_EMPTY)
- cortina_transmit_buffer(port);
-}
-
-static void cortina_uart_stop_rx(struct uart_port *port)
-{
- /* Turn off Rx interrupts. The port lock is held at this point */
- unsigned int reg_v;
-
- reg_v = readl(port->membase + IE);
- writel(reg_v & ~RX_FIFO_NONEMPTYE, port->membase + IE);
-}
-
-static void cortina_uart_enable_ms(struct uart_port *port)
-{
- /* Nope, you really can't hope to attach a modem to this */
-}
-
-static int cortina_uart_startup(struct uart_port *port)
-{
- unsigned int reg_v;
- int retval;
- unsigned long flags;
-
- /* Disable interrupt */
- writel(0, port->membase + IE);
-
- retval =
- request_irq(port->irq, cortina_uart_interrupt, 0, "cortina_uart",
- port);
- if (retval)
- return retval;
-
- spin_lock_irqsave(&port->lock, flags);
-
- reg_v = readl(port->membase + CFG);
- reg_v |= (CFG_UART_EN | CFG_TX_EN | CFG_RX_EN | 0x3 /* 8-bits data */);
- writel(reg_v, port->membase + CFG);
- reg_v = readl(port->membase + IE);
- writel(reg_v | RX_FIFO_NONEMPTYE | TX_FIFO_EMPTYE, port->membase + IE);
-
- spin_unlock_irqrestore(&port->lock, flags);
- return 0;
-}
-
-static void cortina_uart_shutdown(struct uart_port *port)
-{
- cortina_uart_stop_tx(port);
- cortina_uart_stop_rx(port);
- free_irq(port->irq, port);
-}
-
-static void cortina_uart_set_termios(struct uart_port *port,
- struct ktermios *termios,
- struct ktermios *old)
-{
- unsigned long flags;
- int baud;
- unsigned int reg_v, sample_freq = 0;
-
- baud = uart_get_baud_rate(port, termios, old, 0, 230400);
- reg_v = readl(port->membase + CFG);
- /* mask off the baud settings */
- reg_v &= 0xff;
- reg_v |= (port->uartclk / baud) << CFG_BAUD_SART_SHIFT;
-
- /* Sampling rate should be half of baud count */
- sample_freq = (reg_v >> CFG_BAUD_SART_SHIFT) / 2;
-
- /* See include/uapi/asm-generic/termbits.h for CSIZE definition */
- /* mask off the data width */
- reg_v &= 0xfffffffc;
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- reg_v |= 0x0;
- break;
- case CS6:
- reg_v |= 0x1;
- break;
- case CS7:
- reg_v |= 0x2;
- break;
- case CS8:
- default:
- reg_v |= 0x3;
- break;
- }
-
- /* mask off Stop bits */
- reg_v &= ~(CFG_STOP_2BIT);
- if (termios->c_cflag & CSTOPB)
- reg_v |= CFG_STOP_2BIT;
-
- /* Parity */
- reg_v &= ~(CFG_PARITY_EN);
- reg_v |= CFG_PARITY_EVEN;
- if (termios->c_cflag & PARENB) {
- reg_v |= CFG_PARITY_EN;
- if (termios->c_cflag & PARODD)
- reg_v &= ~(CFG_PARITY_EVEN);
- }
-
- spin_lock_irqsave(&port->lock, flags);
- writel(reg_v, port->membase + CFG);
- writel(sample_freq, port->membase + RX_SAMPLE);
- spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *cortina_uart_type(struct uart_port *port)
-{
- return container_of(port, struct cortina_uart_port, uart)->name;
-}
-
-static void cortina_uart_config_port(struct uart_port *port, int flags)
-{
- /*
- * Driver core for serial ports forces a non-zero value for port type.
- * Write an arbitrary value here to accommodate the serial core driver,
- * as ID part of UAPI is redundant.
- */
- port->type = 1;
-}
-
-static int cortina_uart_verify_port(struct uart_port *port,
- struct serial_struct *ser)
-{
- if (ser->type != PORT_UNKNOWN && ser->type != 1)
- return -EINVAL;
- return 0;
-}
-
-static void cortina_access_power(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
- unsigned int reg_v;
-
- /* Read Config register */
- reg_v = readl(port->membase + CFG);
- switch (state) {
- case UART_PM_STATE_ON:
- reg_v |= CFG_UART_EN;
- break;
- case UART_PM_STATE_OFF:
- reg_v &= ~CFG_UART_EN;
- break;
- default:
- pr_err("cortina-access serial: Unknown PM state %d\n", state);
- }
- writel(reg_v, port->membase + CFG);
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-static int cortina_poll_get_char(struct uart_port *port)
-{
- unsigned int rx;
-
- if (readl(port->membase + INFO) & INFO_RX_EMPTY)
- return NO_POLL_CHAR;
-
- rx = readl(port->membase + RX_DAT);
-
- return rx;
-}
-
-static void cortina_poll_put_char(struct uart_port *port, unsigned char c)
-{
- unsigned long time_out;
-
- time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
-
- while (time_before(jiffies, time_out) &&
- (readl(port->membase + INFO) & INFO_TX_FULL))
- cpu_relax();
-
- /* Give up if FIFO stuck! */
- if ((readl(port->membase + INFO) & INFO_TX_FULL))
- return;
-
- writel(c, port->membase + TX_DAT);
-}
-
-#endif
-
-static const struct uart_ops cortina_uart_ops = {
- .tx_empty = cortina_uart_tx_empty,
- .set_mctrl = cortina_uart_set_mctrl,
- .get_mctrl = cortina_uart_get_mctrl,
- .stop_tx = cortina_uart_stop_tx,
- .start_tx = cortina_uart_start_tx,
- .stop_rx = cortina_uart_stop_rx,
- .enable_ms = cortina_uart_enable_ms,
- .startup = cortina_uart_startup,
- .shutdown = cortina_uart_shutdown,
- .set_termios = cortina_uart_set_termios,
- .type = cortina_uart_type,
- .config_port = cortina_uart_config_port,
- .verify_port = cortina_uart_verify_port,
- .pm = cortina_access_power,
-#ifdef CONFIG_CONSOLE_POLL
- .poll_get_char = cortina_poll_get_char,
- .poll_put_char = cortina_poll_put_char,
-#endif
-};
-
-static inline void cortina_uart_interrupt_rx_chars(struct uart_port *port,
- unsigned long status)
-{
- struct tty_port *ttyport = &port->state->port;
- unsigned int ch;
- unsigned int rx, flg;
- struct cortina_uart_port *pca_port;
-
- rx = readl(port->membase + INFO);
- if (INFO_RX_EMPTY & rx)
- return;
-
- if (status & RX_FIFO_OVERRUNE)
- port->icount.overrun++;
-
- pca_port = cortina_uart_get_port(port->line);
-
- /* Read the character while FIFO is not empty */
- do {
- flg = TTY_NORMAL;
- port->icount.rx++;
- ch = readl(port->membase + RX_DAT);
- if (status & RX_PARITY_ERRE) {
- port->icount.parity++;
- flg = TTY_PARITY;
- }
-
- if (pca_port->has_bi) {
- /* If BI supported ? */
- if (status & RX_BREAK) {
- port->icount.brk++;
- if (uart_handle_break(port))
- goto ignore;
- }
- } else {
- /* Treat stop err as BI */
- if (status & RX_STOP_ERRE) {
- port->icount.brk++;
- if (uart_handle_break(port))
- goto ignore;
- }
- }
- if (!(ch & 0x100)) /* RX char is not valid */
- goto ignore;
-
- if (uart_handle_sysrq_char(port, (unsigned char)ch))
- goto ignore;
-
- tty_insert_flip_char(ttyport, ch, flg);
- ignore:
- rx = readl(port->membase + INFO);
- } while (!(INFO_RX_EMPTY & rx));
-
- spin_unlock(&port->lock);
- tty_flip_buffer_push(ttyport);
- spin_lock(&port->lock);
-}
-
-static inline void cortina_uart_interrupt_tx_chars(struct uart_port *port)
-{
- struct circ_buf *xmit = &port->state->xmit;
-
- /* Process out of band chars */
- if (port->x_char) {
- /* Send next char */
- writel(port->x_char, port->membase + TX_DAT);
- goto done;
- }
-
- /* Nothing to do ? */
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- cortina_uart_stop_tx(port);
- goto done;
- }
-
- cortina_transmit_buffer(port);
-
- /* Wake up */
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-
- /* Maybe we're done after all */
- if (uart_circ_empty(xmit))
- cortina_uart_stop_tx(port);
-
- done:
- return;
-}
-
-irqreturn_t cortina_uart_interrupt(int irq, void *dev_id)
-{
- struct uart_port *port = (struct uart_port *)dev_id;
- unsigned int irq_status;
-
- spin_lock(&port->lock);
-
- /* Clear interrupt! */
- irq_status = readl(port->membase + INT);
- writel(irq_status, port->membase + INT);
-
- /* Process any Rx chars first */
- cortina_uart_interrupt_rx_chars(port, irq_status);
- /* Then use any Tx space */
- cortina_uart_interrupt_tx_chars(port);
-
- spin_unlock(&port->lock);
-
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_SERIAL_CORTINA_ACCESS_CONSOLE
-void cortina_console_write(struct console *co, const char *s,
- unsigned int count)
-{
- struct uart_port *port;
- struct cortina_uart_port *pca_port;
- unsigned int i, previous;
- unsigned long flags;
- int locked;
-
- pca_port = cortina_uart_get_port(co->index);
- port = &pca_port->uart;
-
- local_irq_save(flags);
- if (port->sysrq) {
- locked = 0;
- } else if (oops_in_progress) {
- locked = spin_trylock(&port->lock);
- } else {
- spin_lock(&port->lock);
- locked = 1;
- }
-
- /* Save current state */
- previous = readl(port->membase + IE);
- /* Disable Tx interrupts so this all goes out in one go */
- cortina_uart_stop_tx(port);
-
- /* Write all the chars */
- for (i = 0; i < count; i++) {
- /* Wait the TX buffer to be empty, which can't take forever */
- while (!(readl(port->membase + INFO) & INFO_TX_EMPTY))
- cpu_relax();
-
- /* Send the char */
- writel(*s, port->membase + TX_DAT);
-
- /* CR/LF stuff */
- if (*s++ == '\n') {
- /* Wait the TX buffer to be empty */
- while (!(readl(port->membase + INFO) & INFO_TX_EMPTY))
- cpu_relax();
- writel('\r', port->membase + TX_DAT);
- }
- }
-
- writel(previous, port->membase + IE); /* Put it all back */
-
- if (locked)
- spin_unlock(&port->lock);
- local_irq_restore(flags);
-}
-
-static int __init cortina_console_setup(struct console *co, char *options)
-{
- struct uart_port *port;
- struct cortina_uart_port *pca_port;
- int baud = 115200;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- if (co->index < 0 || co->index >= UART_NR)
- return -ENODEV;
-
- pca_port = cortina_uart_get_port(co->index);
- port = &pca_port->uart;
-
- /* This isn't going to do much, but it might change the baud rate. */
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
-
- return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver cortina_uart_driver;
-
-static struct console cortina_console = {
- .name = "ttyS",
- .write = cortina_console_write,
- .device = uart_console_device,
- .setup = cortina_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1, /* Only possible option. */
- .data = &cortina_uart_driver,
-};
-#define CORTINA_CONSOLE (&cortina_console)
-
-/* Support EARLYCON */
-static void cortina_putc(struct uart_port *port, int c)
-{
- unsigned int tmout;
-
- /* No jiffie at early boot stage!
- * Wait up to 5ms for the character to be sent.
- */
- tmout = TX_TIMEOUT;
- while (--tmout) {
- if (!(readl(port->membase + INFO) & INFO_TX_FULL))
- break;
- udelay(1);
- }
-
- /* Give up if FIFO stuck! */
- while ((readl(port->membase + INFO) & INFO_TX_FULL))
- return;
-
- /* Send the char */
- writel(c, port->membase + TX_DAT);
-}
-
-static void cortina_early_write(struct console *con, const char *s,
- unsigned int n)
-{
- struct earlycon_device *dev = con->data;
-
- uart_console_write(&dev->port, s, n, cortina_putc);
-}
-
-static int __init cortina_early_console_setup(struct earlycon_device *device,
- const char *opt)
-{
- if (!device->port.membase)
- return -ENODEV;
-
- device->con->write = cortina_early_write;
- return 0;
-}
-
-EARLYCON_DECLARE(serial, cortina_early_console_setup);
-OF_EARLYCON_DECLARE(serial, "cortina-access,serial", cortina_early_console_setup);
-#else
-#define CORTINA_CONSOLE NULL
-#endif
-
-static struct uart_driver cortina_uart_driver = {
- .owner = THIS_MODULE,
- .driver_name = "cortina-access_uart",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
- .minor = 64,
- .nr = UART_NR,
- .cons = CORTINA_CONSOLE,
-};
-
-/* Match table for of_platform binding */
-static const struct of_device_id cortina_uart_of_match[] = {
- {.compatible = "cortina-access,serial",},
- {}
-};
-MODULE_DEVICE_TABLE(of, cortina_uart_of_match);
-
-static int serial_cortina_probe(struct platform_device *pdev)
-{
- int ret;
- void __iomem *base;
- struct cortina_uart_port *port;
- const struct of_device_id *match;
-
- /* assign DT node pointer */
- struct device_node *np = pdev->dev.of_node;
- struct resource mem_resource;
- u32 of_clock_frequency;
- struct clk *pclk_info;
- int uart_idx;
-
- /* search DT for a match */
- match = of_match_device(cortina_uart_of_match, &pdev->dev);
- if (!match)
- return -EINVAL;
-
- if (cortina_uart_ports == NULL)
- cortina_uart_ports = kzalloc(UART_NR * sizeof(struct cortina_uart_port),
- GFP_KERNEL);
-
- port = cortina_uart_ports;
- for (uart_idx = 0; uart_idx < UART_NR; ++uart_idx) {
- /* Find first empty slot */
- if (strlen(port->name) == 0)
- break;
- port++;
- }
-
- if (uart_idx >= UART_NR)
- return -EINVAL;
-
- snprintf(port->name, sizeof(port->name), "Cortina-Access UART%d", uart_idx);
-
- /* Retrieve HW base address */
- ret = of_address_to_resource(np, 0, &mem_resource);
- if (ret) {
- dev_warn(&pdev->dev, "invalid address %d\n", ret);
- return ret;
- }
-
- base = devm_ioremap(&pdev->dev, mem_resource.start,
- resource_size(&mem_resource));
- if (!base) {
- devm_kfree(&pdev->dev, port);
- return -ENOMEM;
- }
-
- /* assign reg base and irq from DT */
- port->uart.irq = irq_of_parse_and_map(np, 0);
- port->uart.membase = base;
- port->uart.mapbase = mem_resource.start;
- port->uart.ops = &cortina_uart_ops;
- port->uart.dev = &pdev->dev;
- port->uart.line = uart_idx;
- port->uart.has_sysrq = IS_ENABLED(CONFIG_SERIAL_CORTINA_ACCESS_CONSOLE);
-
- /* get clock-freqency tuple from DT and store value */
- if (of_property_read_u32(np, "clock-frequency", &of_clock_frequency)) {
- /* If we are here, it means DT node did not contain
- * clock-frequency tuple. Therefore, instead try to get
- * clk rate through the clk driver that DT has stated
- * we are consuming.
- */
- pclk_info = clk_get(&pdev->dev, NULL);
- if (IS_ERR(pclk_info)) {
- dev_warn(&pdev->dev,
- "clk or clock-frequency not defined\n");
- return PTR_ERR(pclk_info);
- }
-
- clk_prepare_enable(pclk_info);
- of_clock_frequency = clk_get_rate(pclk_info);
- }
- port->uart.uartclk = of_clock_frequency;
-
- if (of_property_read_bool(np, "wakeup-source"))
- port->may_wakeup = true;
- if (of_property_read_bool(np, "break-indicator"))
- port->has_bi = true;
-
- port->uart.type = PORT_UNKNOWN;
-
- if (port->may_wakeup)
- device_init_wakeup(&pdev->dev, true);
-
- ret = uart_add_one_port(&cortina_uart_driver, &port->uart);
- if (ret)
- return ret;
-
- platform_set_drvdata(pdev, port);
-
- return 0;
-}
-
-static int serial_cortina_remove(struct platform_device *pdev)
-{
- struct uart_port *port = platform_get_drvdata(pdev);
- struct cortina_uart_port *pca_port;
-
- if (port) {
- pca_port = cortina_uart_get_port(port->line);
- memset(pca_port->name, 0, CA_UART_NAME_LEN);
- uart_remove_one_port(&cortina_uart_driver, port);
- }
-
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int serial_cortina_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- struct cortina_uart_port *p =
- (struct cortina_uart_port *)pdev->dev.driver_data;
-
- uart_suspend_port(&cortina_uart_driver, &p->uart);
-
- return 0;
-}
-
-static int serial_cortina_resume(struct platform_device *pdev)
-{
- struct cortina_uart_port *p =
- (struct cortina_uart_port *)pdev->dev.driver_data;
-
- uart_resume_port(&cortina_uart_driver, &p->uart);
-
- return 0;
-}
-#else
-#define serial_cortina_suspend NULL
-#define serial_cortina_resume NULL
-#endif
-
-static struct platform_driver serial_cortina_driver = {
- .probe = serial_cortina_probe,
- .remove = serial_cortina_remove,
-#ifdef CONFIG_PM
- .suspend = serial_cortina_suspend,
- .resume = serial_cortina_resume,
-#endif
- .driver = {
- .name = "cortina-access_serial",
- .owner = THIS_MODULE,
- .of_match_table = cortina_uart_of_match,
- },
-};
-
-static int __init cortina_uart_init(void)
-{
- int ret;
-
- ret = uart_register_driver(&cortina_uart_driver);
- if (ret)
- return ret;
-
- ret = platform_driver_register(&serial_cortina_driver);
- if (ret)
- uart_unregister_driver(&cortina_uart_driver);
-
- return ret;
-}
-
-static void __exit cortina_uart_exit(void)
-{
- platform_driver_unregister(&serial_cortina_driver);
- uart_unregister_driver(&cortina_uart_driver);
-}
-
-module_init(cortina_uart_init);
-module_exit(cortina_uart_exit);
-
-MODULE_AUTHOR("Cortina-Access Inc.");
-MODULE_DESCRIPTION(" Cortina-Access UART driver");
-MODULE_LICENSE("GPL");