Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");