^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * UART driver for PNX8XXX SoCs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Per Hallsmark per.hallsmark@mvista.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Ported to 2.6 kernel by EmbeddedAlley
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Reworked by Vitaly Wool <vitalywool@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2000 Deep Blue Solutions Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/sysrq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/tty_flip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/serial_core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/serial.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/serial_pnx8xxx.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* We'll be using StrongARM sa1100 serial port major/minor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define SERIAL_PNX8XXX_MAJOR 204
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define MINOR_START 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define NR_PORTS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define PNX8XXX_ISR_PASS_LIMIT 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * Convert from ignore_status_mask or read_status_mask to FIFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * and interrupt status bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define SM_TO_FIFO(x) ((x) >> 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define SM_TO_ISTAT(x) ((x) & 0x000001ff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define FIFO_TO_SM(x) ((x) << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define ISTAT_TO_SM(x) ((x) & 0x000001ff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * This is the size of our serial port register set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define UART_PORT_SIZE 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * This determines how often we check the modem status signals
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * for any change. They generally aren't connected to an IRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * so we have to poll them. We also check immediately before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * filling the TX fifo incase CTS has been dropped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define MCTRL_TIMEOUT (250*HZ/1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) extern struct pnx8xxx_port pnx8xxx_ports[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static inline int serial_in(struct pnx8xxx_port *sport, int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return (__raw_readl(sport->port.membase + offset));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) __raw_writel(value, sport->port.membase + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * Handle any change of modem status signal since we were last called.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned int status, changed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) status = sport->port.ops->get_mctrl(&sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) changed = status ^ sport->old_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (changed == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) sport->old_status = status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (changed & TIOCM_RI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) sport->port.icount.rng++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (changed & TIOCM_DSR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) sport->port.icount.dsr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (changed & TIOCM_CAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (changed & TIOCM_CTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * This is our per-port timeout handler, for checking the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * modem status signals.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static void pnx8xxx_timeout(struct timer_list *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct pnx8xxx_port *sport = from_timer(sport, t, timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (sport->port.state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) spin_lock_irqsave(&sport->port.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) pnx8xxx_mctrl_check(sport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) spin_unlock_irqrestore(&sport->port.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * interrupts disabled on entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void pnx8xxx_stop_tx(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) u32 ien;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* Disable TX intr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ien = serial_in(sport, PNX8XXX_IEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* Clear all pending TX intr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * interrupts may not be disabled on entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static void pnx8xxx_start_tx(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) u32 ien;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* Clear all pending TX intr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* Enable TX intr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ien = serial_in(sport, PNX8XXX_IEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * Interrupts enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static void pnx8xxx_stop_rx(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) u32 ien;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* Disable RX intr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) ien = serial_in(sport, PNX8XXX_IEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* Clear all pending RX intr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * Set the modem control timer to fire immediately.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) static void pnx8xxx_enable_ms(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) mod_timer(&sport->timer, jiffies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned int status, ch, flg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) sport->port.icount.rx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) flg = TTY_NORMAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * note that the error handling code is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * out of the main execution path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) PNX8XXX_UART_FIFO_RXPAR |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) PNX8XXX_UART_FIFO_RXBRK) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) sport->port.icount.brk++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (uart_handle_break(&sport->port))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) goto ignore_char;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) sport->port.icount.parity++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) sport->port.icount.frame++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) sport->port.icount.overrun++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) status &= sport->port.read_status_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) flg = TTY_PARITY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) flg = TTY_FRAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) sport->port.sysrq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (uart_handle_sysrq_char(&sport->port, ch))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) goto ignore_char;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) uart_insert_char(&sport->port, status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ignore_char:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) PNX8XXX_UART_LCR_RX_NEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) spin_unlock(&sport->port.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) tty_flip_buffer_push(&sport->port.state->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) spin_lock(&sport->port.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct circ_buf *xmit = &sport->port.state->xmit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (sport->port.x_char) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) serial_out(sport, PNX8XXX_FIFO, sport->port.x_char);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) sport->port.icount.tx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) sport->port.x_char = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * Check the modem control lines before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * transmitting anything.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) pnx8xxx_mctrl_check(sport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) pnx8xxx_stop_tx(&sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * TX while bytes available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) while (((serial_in(sport, PNX8XXX_FIFO) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) sport->port.icount.tx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (uart_circ_empty(xmit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) uart_write_wakeup(&sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (uart_circ_empty(xmit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) pnx8xxx_stop_tx(&sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) struct pnx8xxx_port *sport = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) spin_lock(&sport->port.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /* Get the interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) /* Byte or break signal received */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) pnx8xxx_rx_chars(sport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /* TX holding register empty - transmit a byte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (status & PNX8XXX_UART_INT_TX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) pnx8xxx_tx_chars(sport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /* Clear the ISTAT register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) serial_out(sport, PNX8XXX_ICLR, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) spin_unlock(&sport->port.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) * Return TIOCSER_TEMT when transmitter is not busy.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) unsigned int mctrl = TIOCM_DSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) unsigned int msr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) /* REVISIT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) msr = serial_in(sport, PNX8XXX_MCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return mctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) #if 0 /* FIXME */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) unsigned int msr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * Interrupts always disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) unsigned int lcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) spin_lock_irqsave(&sport->port.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) lcr = serial_in(sport, PNX8XXX_LCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (break_state == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) lcr |= PNX8XXX_UART_LCR_TXBREAK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) serial_out(sport, PNX8XXX_LCR, lcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) spin_unlock_irqrestore(&sport->port.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) static int pnx8xxx_startup(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * Allocate the IRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) retval = request_irq(sport->port.irq, pnx8xxx_int, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) "pnx8xxx-uart", sport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * Finally, clear and enable interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) PNX8XXX_UART_INT_ALLTX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) PNX8XXX_UART_INT_ALLRX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) PNX8XXX_UART_INT_ALLTX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * Enable modem status interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) spin_lock_irq(&sport->port.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) pnx8xxx_enable_ms(&sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) spin_unlock_irq(&sport->port.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) static void pnx8xxx_shutdown(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) int lcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * Stop our timer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) del_timer_sync(&sport->timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * Disable all interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) serial_out(sport, PNX8XXX_IEN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) * Reset the Tx and Rx FIFOS, disable the break condition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) lcr = serial_in(sport, PNX8XXX_LCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) serial_out(sport, PNX8XXX_LCR, lcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) * Clear all interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) PNX8XXX_UART_INT_ALLTX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * Free the interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) free_irq(sport->port.irq, sport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) struct ktermios *old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) unsigned int lcr_fcr, old_ien, baud, quot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) * We only support CS7 and CS8.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) while ((termios->c_cflag & CSIZE) != CS7 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) (termios->c_cflag & CSIZE) != CS8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) termios->c_cflag &= ~CSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) termios->c_cflag |= old_csize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) old_csize = CS8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if ((termios->c_cflag & CSIZE) == CS8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) lcr_fcr = PNX8XXX_UART_LCR_8BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) lcr_fcr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (termios->c_cflag & CSTOPB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) lcr_fcr |= PNX8XXX_UART_LCR_2STOPB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (termios->c_cflag & PARENB) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) lcr_fcr |= PNX8XXX_UART_LCR_PAREN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (!(termios->c_cflag & PARODD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) lcr_fcr |= PNX8XXX_UART_LCR_PAREVN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) * Ask the core to calculate the divisor for us.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) quot = uart_get_divisor(port, baud);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) spin_lock_irqsave(&sport->port.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (termios->c_iflag & INPCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) sport->port.read_status_mask |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) sport->port.read_status_mask |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * Characters to ignore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) sport->port.ignore_status_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (termios->c_iflag & IGNPAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) sport->port.ignore_status_mask |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (termios->c_iflag & IGNBRK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) sport->port.ignore_status_mask |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * If we're ignoring parity and break indicators,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * ignore overruns too (for real raw support).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (termios->c_iflag & IGNPAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) sport->port.ignore_status_mask |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * ignore all characters if CREAD is not set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if ((termios->c_cflag & CREAD) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) sport->port.ignore_status_mask |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) del_timer_sync(&sport->timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * Update the per-port timeout.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) uart_update_timeout(port, termios->c_cflag, baud);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * disable interrupts and drain transmitter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) old_ien = serial_in(sport, PNX8XXX_IEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) PNX8XXX_UART_INT_ALLRX));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /* then, disable everything */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) serial_out(sport, PNX8XXX_IEN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) /* Reset the Rx and Tx FIFOs too */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) lcr_fcr |= PNX8XXX_UART_LCR_TX_RST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) lcr_fcr |= PNX8XXX_UART_LCR_RX_RST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) /* set the parity, stop bits and data size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) serial_out(sport, PNX8XXX_LCR, lcr_fcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) /* set the baud rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) quot -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) serial_out(sport, PNX8XXX_BAUD, quot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) serial_out(sport, PNX8XXX_ICLR, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) serial_out(sport, PNX8XXX_IEN, old_ien);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) pnx8xxx_enable_ms(&sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) spin_unlock_irqrestore(&sport->port.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static const char *pnx8xxx_type(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * Release the memory region(s) being used by 'port'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static void pnx8xxx_release_port(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * Request the memory region(s) being used by 'port'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) static int pnx8xxx_request_port(struct uart_port *port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) "pnx8xxx-uart") != NULL ? 0 : -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * Configure/autoconfigure the port.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) static void pnx8xxx_config_port(struct uart_port *port, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (flags & UART_CONFIG_TYPE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) pnx8xxx_request_port(&sport->port) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) sport->port.type = PORT_PNX8XXX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) * Verify the new serial_struct (for TIOCSSERIAL).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) * The only change we allow are to the flags and type, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) * even then only between PORT_PNX8XXX and PORT_UNKNOWN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (sport->port.irq != ser->irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (ser->io_type != SERIAL_IO_MEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (sport->port.uartclk / 16 != ser->baud_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if ((void *)sport->port.mapbase != ser->iomem_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (sport->port.iobase != ser->port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) if (ser->hub6 != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) static const struct uart_ops pnx8xxx_pops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) .tx_empty = pnx8xxx_tx_empty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) .set_mctrl = pnx8xxx_set_mctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) .get_mctrl = pnx8xxx_get_mctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) .stop_tx = pnx8xxx_stop_tx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) .start_tx = pnx8xxx_start_tx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) .stop_rx = pnx8xxx_stop_rx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) .enable_ms = pnx8xxx_enable_ms,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) .break_ctl = pnx8xxx_break_ctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) .startup = pnx8xxx_startup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) .shutdown = pnx8xxx_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) .set_termios = pnx8xxx_set_termios,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) .type = pnx8xxx_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) .release_port = pnx8xxx_release_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) .request_port = pnx8xxx_request_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) .config_port = pnx8xxx_config_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) .verify_port = pnx8xxx_verify_port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * Setup the PNX8XXX serial ports.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) * Note also that we support "console=ttySx" where "x" is either 0 or 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static void __init pnx8xxx_init_ports(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) static int first = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (!first)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) first = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) for (i = 0; i < NR_PORTS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) timer_setup(&pnx8xxx_ports[i].timer, pnx8xxx_timeout, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) pnx8xxx_ports[i].port.ops = &pnx8xxx_pops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) #ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) struct pnx8xxx_port *sport =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) container_of(port, struct pnx8xxx_port, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) /* Wait for UART_TX register to empty */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) status = serial_in(sport, PNX8XXX_FIFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) } while (status & PNX8XXX_UART_FIFO_TXFIFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) serial_out(sport, PNX8XXX_FIFO, ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) * Interrupts are disabled on entering
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) */static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) pnx8xxx_console_write(struct console *co, const char *s, unsigned int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) unsigned int old_ien, status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) * First, save IEN and then disable interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) old_ien = serial_in(sport, PNX8XXX_IEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) PNX8XXX_UART_INT_ALLRX));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * Finally, wait for transmitter to become empty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) * and restore IEN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) /* Wait for UART_TX register to empty */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) status = serial_in(sport, PNX8XXX_FIFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) } while (status & PNX8XXX_UART_FIFO_TXFIFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) /* Clear TX and EMPTY interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) PNX8XXX_UART_INT_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) serial_out(sport, PNX8XXX_IEN, old_ien);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) static int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) pnx8xxx_console_setup(struct console *co, char *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) struct pnx8xxx_port *sport;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) int baud = 38400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) int bits = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) int parity = 'n';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) int flow = 'n';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) * Check whether an invalid uart number has been specified, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) * if so, search for the first available port that does have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * console support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (co->index == -1 || co->index >= NR_PORTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) co->index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) sport = &pnx8xxx_ports[co->index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) uart_parse_options(options, &baud, &parity, &bits, &flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) return uart_set_options(&sport->port, co, baud, parity, bits, flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) static struct uart_driver pnx8xxx_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) static struct console pnx8xxx_console = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) .name = "ttyS",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) .write = pnx8xxx_console_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) .device = uart_console_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) .setup = pnx8xxx_console_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) .flags = CON_PRINTBUFFER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) .index = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) .data = &pnx8xxx_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) static int __init pnx8xxx_rs_console_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) pnx8xxx_init_ports();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) register_console(&pnx8xxx_console);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) console_initcall(pnx8xxx_rs_console_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) #define PNX8XXX_CONSOLE &pnx8xxx_console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) #define PNX8XXX_CONSOLE NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) static struct uart_driver pnx8xxx_reg = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) .driver_name = "ttyS",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) .dev_name = "ttyS",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) .major = SERIAL_PNX8XXX_MAJOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) .minor = MINOR_START,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) .nr = NR_PORTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) .cons = PNX8XXX_CONSOLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) return uart_suspend_port(&pnx8xxx_reg, &sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) static int pnx8xxx_serial_resume(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) return uart_resume_port(&pnx8xxx_reg, &sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) static int pnx8xxx_serial_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) struct resource *res = pdev->resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) for (i = 0; i < pdev->num_resources; i++, res++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (!(res->flags & IORESOURCE_MEM))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) for (i = 0; i < NR_PORTS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) if (pnx8xxx_ports[i].port.mapbase != res->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) pnx8xxx_ports[i].port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_PNX8XXX_CONSOLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) pnx8xxx_ports[i].port.dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) platform_set_drvdata(pdev, &pnx8xxx_ports[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) static int pnx8xxx_serial_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (sport)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) uart_remove_one_port(&pnx8xxx_reg, &sport->port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) static struct platform_driver pnx8xxx_serial_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) .name = "pnx8xxx-uart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) .probe = pnx8xxx_serial_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) .remove = pnx8xxx_serial_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) .suspend = pnx8xxx_serial_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) .resume = pnx8xxx_serial_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) static int __init pnx8xxx_serial_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) printk(KERN_INFO "Serial: PNX8XXX driver\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) pnx8xxx_init_ports();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) ret = uart_register_driver(&pnx8xxx_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) ret = platform_driver_register(&pnx8xxx_serial_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) uart_unregister_driver(&pnx8xxx_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) static void __exit pnx8xxx_serial_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) platform_driver_unregister(&pnx8xxx_serial_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) uart_unregister_driver(&pnx8xxx_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) module_init(pnx8xxx_serial_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) module_exit(pnx8xxx_serial_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) MODULE_ALIAS("platform:pnx8xxx-uart");