Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (25 commits)
  serial: Tidy REMOTE_DEBUG
  serial: isicomm: handle running out of slots
  serial: bfin_sport_uart: Use resource size to fix off-by-one error
  tty: fix obsolete comment on tty_insert_flip_string_fixed_flag
  serial: Add driver for the Altera UART
  serial: Add driver for the Altera JTAG UART
  serial: timbuart: make sure last byte is sent when port is closed
  serial: two branches the same in timbuart_set_mctrl()
  serial: uartlite: move from byte accesses to word accesses
  tty: n_gsm: depends on NET
  tty: n_gsm line discipline
  serial: TTY: new ldiscs for staging
  serial: bfin_sport_uart: drop redundant cpu depends
  serial: bfin_sport_uart: drop the experimental markings
  serial: bfin_sport_uart: pull in bfin_sport.h for SPORT defines
  serial: bfin_sport_uart: only enable SPORT TX if data is to be sent
  serial: bfin_sport_uart: drop useless status masks
  serial: bfin_sport_uart: zero sport_uart_port if allocated dynamically
  serial: bfin_sport_uart: protect changes to uart_port
  serial: bfin_sport_uart: add support for CTS/RTS via GPIOs
  ...
This commit is contained in:
Linus Torvalds 2010-05-21 10:48:48 -07:00
commit 7f02ab3ce3
19 changed files with 4196 additions and 324 deletions

View File

@ -276,11 +276,19 @@ config N_HDLC
Allows synchronous HDLC communications with tty device drivers that Allows synchronous HDLC communications with tty device drivers that
support synchronous HDLC such as the Microgate SyncLink adapter. support synchronous HDLC such as the Microgate SyncLink adapter.
This driver can only be built as a module ( = code which can be This driver can be built as a module ( = code which can be
inserted in and removed from the running kernel whenever you want). inserted in and removed from the running kernel whenever you want).
The module will be called n_hdlc. If you want to do that, say M The module will be called n_hdlc. If you want to do that, say M
here. here.
config N_GSM
tristate "GSM MUX line discipline support (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on NET
help
This line discipline provides support for the GSM MUX protocol and
presents the mux as a set of 61 individual tty devices.
config RISCOM8 config RISCOM8
tristate "SDL RISCom/8 card support" tristate "SDL RISCom/8 card support"
depends on SERIAL_NONSTANDARD depends on SERIAL_NONSTANDARD

View File

@ -40,6 +40,7 @@ obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o

View File

@ -1573,11 +1573,16 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device); dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
/* allot the first empty slot in the array */ /* allot the first empty slot in the array */
for (index = 0; index < BOARD_COUNT; index++) for (index = 0; index < BOARD_COUNT; index++) {
if (isi_card[index].base == 0) { if (isi_card[index].base == 0) {
board = &isi_card[index]; board = &isi_card[index];
break; break;
} }
}
if (index == BOARD_COUNT) {
retval = -ENODEV;
goto err_disable;
}
board->index = index; board->index = index;
board->base = pci_resource_start(pdev, 3); board->base = pci_resource_start(pdev, 3);
@ -1624,6 +1629,7 @@ errunrr:
errdec: errdec:
board->base = 0; board->base = 0;
card_count--; card_count--;
err_disable:
pci_disable_device(pdev); pci_disable_device(pdev);
err: err:
return retval; return retval;

2763
drivers/char/n_gsm.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -176,23 +176,6 @@ static void config_setup(struct cyclades_port *);
static void show_status(int); static void show_status(int);
#endif #endif
#ifdef CONFIG_REMOTE_DEBUG
static void debug_setup(void);
void queueDebugChar(int c);
int getDebugChar(void);
#define DEBUG_PORT 1
#define DEBUG_LEN 256
typedef struct {
int in;
int out;
unsigned char buf[DEBUG_LEN];
} debugq;
debugq debugiq;
#endif
/* /*
* I have my own version of udelay(), as it is needed when initialising * I have my own version of udelay(), as it is needed when initialising
* the chip, before the delay loop has been calibrated. Should probably * the chip, before the delay loop has been calibrated. Should probably
@ -515,11 +498,6 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
/* determine the channel and change to that context */ /* determine the channel and change to that context */
channel = (u_short) (base_addr[CyLICR] >> 2); channel = (u_short) (base_addr[CyLICR] >> 2);
#ifdef CONFIG_REMOTE_DEBUG
if (channel == DEBUG_PORT) {
panic("TxInt on debug port!!!");
}
#endif
/* validate the port number (as configured and open) */ /* validate the port number (as configured and open) */
if ((channel < 0) || (NR_PORTS <= channel)) { if ((channel < 0) || (NR_PORTS <= channel)) {
base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
@ -634,14 +612,6 @@ static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
info->last_active = jiffies; info->last_active = jiffies;
save_cnt = char_count = base_addr[CyRFOC]; save_cnt = char_count = base_addr[CyRFOC];
#ifdef CONFIG_REMOTE_DEBUG
if (channel == DEBUG_PORT) {
while (char_count--) {
data = base_addr[CyRDR];
queueDebugChar(data);
}
} else
#endif
/* if there is nowhere to put the data, discard it */ /* if there is nowhere to put the data, discard it */
if (info->tty == 0) { if (info->tty == 0) {
while (char_count--) { while (char_count--) {
@ -2195,9 +2165,7 @@ static int __init serial167_init(void)
port_num++; port_num++;
info++; info++;
} }
#ifdef CONFIG_REMOTE_DEBUG
debug_setup();
#endif
ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0, ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
"cd2401_errors", cd2401_rxerr_interrupt); "cd2401_errors", cd2401_rxerr_interrupt);
if (ret) { if (ret) {
@ -2518,193 +2486,4 @@ static int __init serial167_console_init(void)
console_initcall(serial167_console_init); console_initcall(serial167_console_init);
#ifdef CONFIG_REMOTE_DEBUG
void putDebugChar(int c)
{
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
volatile u_char sink;
u_char ier;
int port;
local_irq_save(flags);
/* Ensure transmitter is enabled! */
port = DEBUG_PORT;
base_addr[CyCAR] = (u_char) port;
while (base_addr[CyCCR])
;
base_addr[CyCCR] = CyENB_XMTR;
ier = base_addr[CyIER];
base_addr[CyIER] = CyTxMpty;
while (1) {
if (pcc2chip[PccSCCTICR] & 0x20) {
/* We have a Tx int. Acknowledge it */
sink = pcc2chip[PccTPIACKR];
if ((base_addr[CyLICR] >> 2) == port) {
base_addr[CyTDR] = c;
base_addr[CyTEOIR] = 0;
break;
} else
base_addr[CyTEOIR] = CyNOTRANS;
}
}
base_addr[CyIER] = ier;
local_irq_restore(flags);
}
int getDebugChar()
{
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
volatile u_char sink;
u_char ier;
int port;
int i, c;
i = debugiq.out;
if (i != debugiq.in) {
c = debugiq.buf[i];
if (++i == DEBUG_LEN)
i = 0;
debugiq.out = i;
return c;
}
/* OK, nothing in queue, wait in poll loop */
local_irq_save(flags);
/* Ensure receiver is enabled! */
port = DEBUG_PORT;
base_addr[CyCAR] = (u_char) port;
#if 0
while (base_addr[CyCCR])
;
base_addr[CyCCR] = CyENB_RCVR;
#endif
ier = base_addr[CyIER];
base_addr[CyIER] = CyRxData;
while (1) {
if (pcc2chip[PccSCCRICR] & 0x20) {
/* We have a Rx int. Acknowledge it */
sink = pcc2chip[PccRPIACKR];
if ((base_addr[CyLICR] >> 2) == port) {
int cnt = base_addr[CyRFOC];
while (cnt-- > 0) {
c = base_addr[CyRDR];
if (c == 0)
printk
("!! debug char is null (cnt=%d) !!",
cnt);
else
queueDebugChar(c);
}
base_addr[CyREOIR] = 0;
i = debugiq.out;
if (i == debugiq.in)
panic("Debug input queue empty!");
c = debugiq.buf[i];
if (++i == DEBUG_LEN)
i = 0;
debugiq.out = i;
break;
} else
base_addr[CyREOIR] = CyNOTRANS;
}
}
base_addr[CyIER] = ier;
local_irq_restore(flags);
return (c);
}
void queueDebugChar(int c)
{
int i;
i = debugiq.in;
debugiq.buf[i] = c;
if (++i == DEBUG_LEN)
i = 0;
if (i != debugiq.out)
debugiq.in = i;
}
static void debug_setup()
{
unsigned long flags;
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
int i, cflag;
cflag = B19200;
local_irq_save(flags);
for (i = 0; i < 4; i++) {
base_addr[CyCAR] = i;
base_addr[CyLICR] = i << 2;
}
debugiq.in = debugiq.out = 0;
base_addr[CyCAR] = DEBUG_PORT;
/* baud rate */
i = cflag & CBAUD;
base_addr[CyIER] = 0;
base_addr[CyCMR] = CyASYNC;
base_addr[CyLICR] = DEBUG_PORT << 2;
base_addr[CyLIVR] = 0x5c;
/* tx and rx baud rate */
base_addr[CyTCOR] = baud_co[i];
base_addr[CyTBPR] = baud_bpr[i];
base_addr[CyRCOR] = baud_co[i] >> 5;
base_addr[CyRBPR] = baud_bpr[i];
/* set line characteristics according configuration */
base_addr[CySCHR1] = 0;
base_addr[CySCHR2] = 0;
base_addr[CySCRL] = 0;
base_addr[CySCRH] = 0;
base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
base_addr[CyCOR2] = 0;
base_addr[CyCOR3] = Cy_1_STOP;
base_addr[CyCOR4] = baud_cor4[i];
base_addr[CyCOR5] = 0;
base_addr[CyCOR6] = 0;
base_addr[CyCOR7] = 0;
write_cy_cmd(base_addr, CyINIT_CHAN);
write_cy_cmd(base_addr, CyENB_RCVR);
base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
base_addr[CyRTPRL] = 2;
base_addr[CyRTPRH] = 0;
base_addr[CyMSVR1] = CyRTS;
base_addr[CyMSVR2] = CyDTR;
base_addr[CyIER] = CyRxData;
local_irq_restore(flags);
} /* debug_setup */
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -238,7 +238,7 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
* @size: size * @size: size
* *
* Queue a series of bytes to the tty buffering. All the characters * Queue a series of bytes to the tty buffering. All the characters
* passed are marked as without error. Returns the number added. * passed are marked with the supplied flag. Returns the number added.
* *
* Locking: Called functions may take tty->buf.lock * Locking: Called functions may take tty->buf.lock
*/ */

View File

@ -1423,8 +1423,8 @@ config SERIAL_SC26XX_CONSOLE
Support for Console on SC2681/SC2692 serial ports. Support for Console on SC2681/SC2692 serial ports.
config SERIAL_BFIN_SPORT config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)" tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN && EXPERIMENTAL depends on BLACKFIN
select SERIAL_CORE select SERIAL_CORE
help help
Enable SPORT emulate UART on Blackfin series. Enable SPORT emulate UART on Blackfin series.
@ -1439,28 +1439,52 @@ config SERIAL_BFIN_SPORT_CONSOLE
config SERIAL_BFIN_SPORT0_UART config SERIAL_BFIN_SPORT0_UART
bool "Enable UART over SPORT0" bool "Enable UART over SPORT0"
depends on SERIAL_BFIN_SPORT && !(BF542 || BF542M || BF544 || BF544M) depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
help help
Enable UART over SPORT0 Enable UART over SPORT0
config SERIAL_BFIN_SPORT0_UART_CTSRTS
bool "Enable UART over SPORT0 hardware flow control"
depends on SERIAL_BFIN_SPORT0_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT1_UART config SERIAL_BFIN_SPORT1_UART
bool "Enable UART over SPORT1" bool "Enable UART over SPORT1"
depends on SERIAL_BFIN_SPORT depends on SERIAL_BFIN_SPORT
help help
Enable UART over SPORT1 Enable UART over SPORT1
config SERIAL_BFIN_SPORT1_UART_CTSRTS
bool "Enable UART over SPORT1 hardware flow control"
depends on SERIAL_BFIN_SPORT1_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT2_UART config SERIAL_BFIN_SPORT2_UART
bool "Enable UART over SPORT2" bool "Enable UART over SPORT2"
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
help help
Enable UART over SPORT2 Enable UART over SPORT2
config SERIAL_BFIN_SPORT2_UART_CTSRTS
bool "Enable UART over SPORT2 hardware flow control"
depends on SERIAL_BFIN_SPORT2_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT3_UART config SERIAL_BFIN_SPORT3_UART
bool "Enable UART over SPORT3" bool "Enable UART over SPORT3"
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
help help
Enable UART over SPORT3 Enable UART over SPORT3
config SERIAL_BFIN_SPORT3_UART_CTSRTS
bool "Enable UART over SPORT3 hardware flow control"
depends on SERIAL_BFIN_SPORT3_UART
help
Enable hardware flow control in the driver.
config SERIAL_TIMBERDALE config SERIAL_TIMBERDALE
tristate "Support for timberdale UART" tristate "Support for timberdale UART"
select SERIAL_CORE select SERIAL_CORE
@ -1499,4 +1523,56 @@ config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
help help
Support for running a console on the GRLIB APBUART Support for running a console on the GRLIB APBUART
config SERIAL_ALTERA_JTAGUART
tristate "Altera JTAG UART support"
select SERIAL_CORE
help
This driver supports the Altera JTAG UART port.
config SERIAL_ALTERA_JTAGUART_CONSOLE
bool "Altera JTAG UART console support"
depends on SERIAL_ALTERA_JTAGUART=y
select SERIAL_CORE_CONSOLE
help
Enable a Altera JTAG UART port to be the system console.
config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
bool "Bypass output when no connection"
depends on SERIAL_ALTERA_JTAGUART_CONSOLE
select SERIAL_CORE_CONSOLE
help
Bypass console output and keep going even if there is no
JTAG terminal connection with the host.
config SERIAL_ALTERA_UART
tristate "Altera UART support"
select SERIAL_CORE
help
This driver supports the Altera softcore UART port.
config SERIAL_ALTERA_UART_MAXPORTS
int "Maximum number of Altera UART ports"
depends on SERIAL_ALTERA_UART
default 4
help
This setting lets you define the maximum number of the Altera
UART ports. The usual default varies from board to board, and
this setting is a way of catering for that.
config SERIAL_ALTERA_UART_BAUDRATE
int "Default baudrate for Altera UART ports"
depends on SERIAL_ALTERA_UART
default 115200
help
This setting lets you define what the default baudrate is for the
Altera UART ports. The usual default varies from board to board,
and this setting is a way of catering for that.
config SERIAL_ALTERA_UART_CONSOLE
bool "Altera UART console support"
depends on SERIAL_ALTERA_UART=y
select SERIAL_CORE_CONSOLE
help
Enable a Altera UART port to be the system console.
endmenu endmenu

View File

@ -82,3 +82,5 @@ obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o

View File

@ -0,0 +1,504 @@
/*
* altera_jtaguart.c -- Altera JTAG UART driver
*
* Based on mcf.c -- Freescale ColdFire UART driver
*
* (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
* (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
* (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/altera_jtaguart.h>
#define DRV_NAME "altera_jtaguart"
/*
* Altera JTAG UART register definitions according to the Altera JTAG UART
* datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
*/
#define ALTERA_JTAGUART_SIZE 8
#define ALTERA_JTAGUART_DATA_REG 0
#define ALTERA_JTAGUART_DATA_DATA_MSK 0x000000FF
#define ALTERA_JTAGUART_DATA_RVALID_MSK 0x00008000
#define ALTERA_JTAGUART_DATA_RAVAIL_MSK 0xFFFF0000
#define ALTERA_JTAGUART_DATA_RAVAIL_OFF 16
#define ALTERA_JTAGUART_CONTROL_REG 4
#define ALTERA_JTAGUART_CONTROL_RE_MSK 0x00000001
#define ALTERA_JTAGUART_CONTROL_WE_MSK 0x00000002
#define ALTERA_JTAGUART_CONTROL_RI_MSK 0x00000100
#define ALTERA_JTAGUART_CONTROL_RI_OFF 8
#define ALTERA_JTAGUART_CONTROL_WI_MSK 0x00000200
#define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400
#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000
#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF 16
/*
* Local per-uart structure.
*/
struct altera_jtaguart {
struct uart_port port;
unsigned int sigs; /* Local copy of line sigs */
unsigned long imr; /* Local IMR mirror */
};
static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
{
return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
}
static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
{
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
{
}
static void altera_jtaguart_start_tx(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_stop_tx(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_stop_rx(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
{
}
static void altera_jtaguart_enable_ms(struct uart_port *port)
{
}
static void altera_jtaguart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
/* Just copy the old termios settings back */
if (old)
tty_termios_copy_hw(termios, old);
}
static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
{
struct uart_port *port = &pp->port;
unsigned char ch, flag;
unsigned long status;
while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
ALTERA_JTAGUART_DATA_RVALID_MSK) {
ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
flag = TTY_NORMAL;
port->icount.rx++;
if (uart_handle_sysrq_char(port, ch))
continue;
uart_insert_char(port, 0, 0, ch, flag);
}
tty_flip_buffer_push(port->state->port.tty);
}
static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
{
struct uart_port *port = &pp->port;
struct circ_buf *xmit = &port->state->xmit;
unsigned int pending, count;
if (port->x_char) {
/* Send special char - probably flow control */
writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
port->x_char = 0;
port->icount.tx++;
return;
}
pending = uart_circ_chars_pending(xmit);
if (pending > 0) {
count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
if (count > pending)
count = pending;
if (count > 0) {
pending -= count;
while (count--) {
writel(xmit->buf[xmit->tail],
port->membase + ALTERA_JTAGUART_DATA_REG);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (pending < WAKEUP_CHARS)
uart_write_wakeup(port);
}
}
if (pending == 0) {
pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
}
static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
{
struct uart_port *port = data;
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
unsigned int isr;
isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
spin_lock(&port->lock);
if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
altera_jtaguart_rx_chars(pp);
if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
altera_jtaguart_tx_chars(pp);
spin_unlock(&port->lock);
return IRQ_RETVAL(isr);
}
static void altera_jtaguart_config_port(struct uart_port *port, int flags)
{
port->type = PORT_ALTERA_JTAGUART;
/* Clear mask, so no surprise interrupts. */
writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static int altera_jtaguart_startup(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
unsigned long flags;
int ret;
ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
DRV_NAME, port);
if (ret) {
pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
"interrupt vector=%d\n", port->line, port->irq);
return ret;
}
spin_lock_irqsave(&port->lock, flags);
/* Enable RX interrupts now */
pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
static void altera_jtaguart_shutdown(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* Disable all interrupts now */
pp->imr = 0;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
free_irq(port->irq, port);
}
static const char *altera_jtaguart_type(struct uart_port *port)
{
return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
}
static int altera_jtaguart_request_port(struct uart_port *port)
{
/* UARTs always present */
return 0;
}
static void altera_jtaguart_release_port(struct uart_port *port)
{
/* Nothing to release... */
}
static int altera_jtaguart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
return -EINVAL;
return 0;
}
/*
* Define the basic serial functions we support.
*/
static struct uart_ops altera_jtaguart_ops = {
.tx_empty = altera_jtaguart_tx_empty,
.get_mctrl = altera_jtaguart_get_mctrl,
.set_mctrl = altera_jtaguart_set_mctrl,
.start_tx = altera_jtaguart_start_tx,
.stop_tx = altera_jtaguart_stop_tx,
.stop_rx = altera_jtaguart_stop_rx,
.enable_ms = altera_jtaguart_enable_ms,
.break_ctl = altera_jtaguart_break_ctl,
.startup = altera_jtaguart_startup,
.shutdown = altera_jtaguart_shutdown,
.set_termios = altera_jtaguart_set_termios,
.type = altera_jtaguart_type,
.request_port = altera_jtaguart_request_port,
.release_port = altera_jtaguart_release_port,
.config_port = altera_jtaguart_config_port,
.verify_port = altera_jtaguart_verify_port,
};
#define ALTERA_JTAGUART_MAXPORTS 1
static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
*platp)
{
struct uart_port *port;
int i;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_jtaguart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_JTAGUART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->flags = ASYNC_BOOT_AUTOCONF;
port->ops = &altera_jtaguart_ops;
}
return 0;
}
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
static void altera_jtaguart_console_putc(struct console *co, const char c)
{
struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
unsigned long status;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
spin_unlock_irqrestore(&port->lock, flags);
return; /* no connection activity */
}
spin_unlock_irqrestore(&port->lock, flags);
cpu_relax();
spin_lock_irqsave(&port->lock, flags);
}
writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
#else
static void altera_jtaguart_console_putc(struct console *co, const char c)
{
struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
spin_unlock_irqrestore(&port->lock, flags);
cpu_relax();
spin_lock_irqsave(&port->lock, flags);
}
writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
#endif
static void altera_jtaguart_console_write(struct console *co, const char *s,
unsigned int count)
{
for (; count; count--, s++) {
altera_jtaguart_console_putc(co, *s);
if (*s == '\n')
altera_jtaguart_console_putc(co, '\r');
}
}
static int __init altera_jtaguart_console_setup(struct console *co,
char *options)
{
struct uart_port *port;
if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
return -EINVAL;
port = &altera_jtaguart_ports[co->index].port;
if (port->membase == 0)
return -ENODEV;
return 0;
}
static struct uart_driver altera_jtaguart_driver;
static struct console altera_jtaguart_console = {
.name = "ttyJ",
.write = altera_jtaguart_console_write,
.device = uart_console_device,
.setup = altera_jtaguart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &altera_jtaguart_driver,
};
static int __init altera_jtaguart_console_init(void)
{
register_console(&altera_jtaguart_console);
return 0;
}
console_initcall(altera_jtaguart_console_init);
#define ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
#else
#define ALTERA_JTAGUART_CONSOLE NULL
#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
static struct uart_driver altera_jtaguart_driver = {
.owner = THIS_MODULE,
.driver_name = "altera_jtaguart",
.dev_name = "ttyJ",
.major = ALTERA_JTAGUART_MAJOR,
.minor = ALTERA_JTAGUART_MINOR,
.nr = ALTERA_JTAGUART_MAXPORTS,
.cons = ALTERA_JTAGUART_CONSOLE,
};
static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
{
struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
struct uart_port *port;
int i;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_jtaguart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_JTAGUART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->ops = &altera_jtaguart_ops;
port->flags = ASYNC_BOOT_AUTOCONF;
uart_add_one_port(&altera_jtaguart_driver, port);
}
return 0;
}
static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
port = &altera_jtaguart_ports[i].port;
if (port)
uart_remove_one_port(&altera_jtaguart_driver, port);
}
return 0;
}
static struct platform_driver altera_jtaguart_platform_driver = {
.probe = altera_jtaguart_probe,
.remove = __devexit_p(altera_jtaguart_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __init altera_jtaguart_init(void)
{
int rc;
rc = uart_register_driver(&altera_jtaguart_driver);
if (rc)
return rc;
rc = platform_driver_register(&altera_jtaguart_platform_driver);
if (rc) {
uart_unregister_driver(&altera_jtaguart_driver);
return rc;
}
return 0;
}
static void __exit altera_jtaguart_exit(void)
{
platform_driver_unregister(&altera_jtaguart_platform_driver);
uart_unregister_driver(&altera_jtaguart_driver);
}
module_init(altera_jtaguart_init);
module_exit(altera_jtaguart_exit);
MODULE_DESCRIPTION("Altera JTAG UART driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -0,0 +1,570 @@
/*
* altera_uart.c -- Altera UART driver
*
* Based on mcf.c -- Freescale ColdFire UART driver
*
* (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
* (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
* (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/altera_uart.h>
#define DRV_NAME "altera_uart"
/*
* Altera UART register definitions according to the Nios UART datasheet:
* http://www.altera.com/literature/ds/ds_nios_uart.pdf
*/
#define ALTERA_UART_SIZE 32
#define ALTERA_UART_RXDATA_REG 0
#define ALTERA_UART_TXDATA_REG 4
#define ALTERA_UART_STATUS_REG 8
#define ALTERA_UART_CONTROL_REG 12
#define ALTERA_UART_DIVISOR_REG 16
#define ALTERA_UART_EOP_REG 20
#define ALTERA_UART_STATUS_PE_MSK 0x0001 /* parity error */
#define ALTERA_UART_STATUS_FE_MSK 0x0002 /* framing error */
#define ALTERA_UART_STATUS_BRK_MSK 0x0004 /* break */
#define ALTERA_UART_STATUS_ROE_MSK 0x0008 /* RX overrun error */
#define ALTERA_UART_STATUS_TOE_MSK 0x0010 /* TX overrun error */
#define ALTERA_UART_STATUS_TMT_MSK 0x0020 /* TX shift register state */
#define ALTERA_UART_STATUS_TRDY_MSK 0x0040 /* TX ready */
#define ALTERA_UART_STATUS_RRDY_MSK 0x0080 /* RX ready */
#define ALTERA_UART_STATUS_E_MSK 0x0100 /* exception condition */
#define ALTERA_UART_STATUS_DCTS_MSK 0x0400 /* CTS logic-level change */
#define ALTERA_UART_STATUS_CTS_MSK 0x0800 /* CTS logic state */
#define ALTERA_UART_STATUS_EOP_MSK 0x1000 /* EOP written/read */
/* Enable interrupt on... */
#define ALTERA_UART_CONTROL_PE_MSK 0x0001 /* ...parity error */
#define ALTERA_UART_CONTROL_FE_MSK 0x0002 /* ...framing error */
#define ALTERA_UART_CONTROL_BRK_MSK 0x0004 /* ...break */
#define ALTERA_UART_CONTROL_ROE_MSK 0x0008 /* ...RX overrun */
#define ALTERA_UART_CONTROL_TOE_MSK 0x0010 /* ...TX overrun */
#define ALTERA_UART_CONTROL_TMT_MSK 0x0020 /* ...TX shift register empty */
#define ALTERA_UART_CONTROL_TRDY_MSK 0x0040 /* ...TX ready */
#define ALTERA_UART_CONTROL_RRDY_MSK 0x0080 /* ...RX ready */
#define ALTERA_UART_CONTROL_E_MSK 0x0100 /* ...exception*/
#define ALTERA_UART_CONTROL_TRBK_MSK 0x0200 /* TX break */
#define ALTERA_UART_CONTROL_DCTS_MSK 0x0400 /* Interrupt on CTS change */
#define ALTERA_UART_CONTROL_RTS_MSK 0x0800 /* RTS signal */
#define ALTERA_UART_CONTROL_EOP_MSK 0x1000 /* Interrupt on EOP */
/*
* Local per-uart structure.
*/
struct altera_uart {
struct uart_port port;
unsigned int sigs; /* Local copy of line sigs */
unsigned short imr; /* Local IMR mirror */
};
static unsigned int altera_uart_tx_empty(struct uart_port *port)
{
return (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
}
static unsigned int altera_uart_get_mctrl(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
unsigned int sigs;
spin_lock_irqsave(&port->lock, flags);
sigs =
(readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
sigs |= (pp->sigs & TIOCM_RTS);
spin_unlock_irqrestore(&port->lock, flags);
return sigs;
}
static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->sigs = sigs;
if (sigs & TIOCM_RTS)
pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
else
pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_start_tx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_stop_tx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_stop_rx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_break_ctl(struct uart_port *port, int break_state)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if (break_state == -1)
pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
else
pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_enable_ms(struct uart_port *port)
{
}
static void altera_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned long flags;
unsigned int baud, baudclk;
baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
baudclk = port->uartclk / baud;
if (old)
tty_termios_copy_hw(termios, old);
tty_termios_encode_baud_rate(termios, baud, baud);
spin_lock_irqsave(&port->lock, flags);
writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_rx_chars(struct altera_uart *pp)
{
struct uart_port *port = &pp->port;
unsigned char ch, flag;
unsigned short status;
while ((status = readl(port->membase + ALTERA_UART_STATUS_REG)) &
ALTERA_UART_STATUS_RRDY_MSK) {
ch = readl(port->membase + ALTERA_UART_RXDATA_REG);
flag = TTY_NORMAL;
port->icount.rx++;
if (status & ALTERA_UART_STATUS_E_MSK) {
writel(status, port->membase + ALTERA_UART_STATUS_REG);
if (status & ALTERA_UART_STATUS_BRK_MSK) {
port->icount.brk++;
if (uart_handle_break(port))
continue;
} else if (status & ALTERA_UART_STATUS_PE_MSK) {
port->icount.parity++;
} else if (status & ALTERA_UART_STATUS_ROE_MSK) {
port->icount.overrun++;
} else if (status & ALTERA_UART_STATUS_FE_MSK) {
port->icount.frame++;
}
status &= port->read_status_mask;
if (status & ALTERA_UART_STATUS_BRK_MSK)
flag = TTY_BREAK;
else if (status & ALTERA_UART_STATUS_PE_MSK)
flag = TTY_PARITY;
else if (status & ALTERA_UART_STATUS_FE_MSK)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, ch))
continue;
uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
flag);
}
tty_flip_buffer_push(port->state->port.tty);
}
static void altera_uart_tx_chars(struct altera_uart *pp)
{
struct uart_port *port = &pp->port;
struct circ_buf *xmit = &port->state->xmit;
if (port->x_char) {
/* Send special char - probably flow control */
writel(port->x_char, port->membase + ALTERA_UART_TXDATA_REG);
port->x_char = 0;
port->icount.tx++;
return;
}
while (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK) {
if (xmit->head == xmit->tail)
break;
writel(xmit->buf[xmit->tail],
port->membase + ALTERA_UART_TXDATA_REG);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (xmit->head == xmit->tail) {
pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
}
}
static irqreturn_t altera_uart_interrupt(int irq, void *data)
{
struct uart_port *port = data;
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned int isr;
isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr;
if (isr & ALTERA_UART_STATUS_RRDY_MSK)
altera_uart_rx_chars(pp);
if (isr & ALTERA_UART_STATUS_TRDY_MSK)
altera_uart_tx_chars(pp);
return IRQ_RETVAL(isr);
}
static void altera_uart_config_port(struct uart_port *port, int flags)
{
port->type = PORT_ALTERA_UART;
/* Clear mask, so no surprise interrupts. */
writel(0, port->membase + ALTERA_UART_CONTROL_REG);
/* Clear status register */
writel(0, port->membase + ALTERA_UART_STATUS_REG);
}
static int altera_uart_startup(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
int ret;
ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
DRV_NAME, port);
if (ret) {
pr_err(DRV_NAME ": unable to attach Altera UART %d "
"interrupt vector=%d\n", port->line, port->irq);
return ret;
}
spin_lock_irqsave(&port->lock, flags);
/* Enable RX interrupts now */
pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
static void altera_uart_shutdown(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* Disable all interrupts now */
pp->imr = 0;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
free_irq(port->irq, port);
}
static const char *altera_uart_type(struct uart_port *port)
{
return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
}
static int altera_uart_request_port(struct uart_port *port)
{
/* UARTs always present */
return 0;
}
static void altera_uart_release_port(struct uart_port *port)
{
/* Nothing to release... */
}
static int altera_uart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
return -EINVAL;
return 0;
}
/*
* Define the basic serial functions we support.
*/
static struct uart_ops altera_uart_ops = {
.tx_empty = altera_uart_tx_empty,
.get_mctrl = altera_uart_get_mctrl,
.set_mctrl = altera_uart_set_mctrl,
.start_tx = altera_uart_start_tx,
.stop_tx = altera_uart_stop_tx,
.stop_rx = altera_uart_stop_rx,
.enable_ms = altera_uart_enable_ms,
.break_ctl = altera_uart_break_ctl,
.startup = altera_uart_startup,
.shutdown = altera_uart_shutdown,
.set_termios = altera_uart_set_termios,
.type = altera_uart_type,
.request_port = altera_uart_request_port,
.release_port = altera_uart_release_port,
.config_port = altera_uart_config_port,
.verify_port = altera_uart_verify_port,
};
static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
{
struct uart_port *port;
int i;
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_uart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_UART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = platp[i].uartclk;
port->flags = ASYNC_BOOT_AUTOCONF;
port->ops = &altera_uart_ops;
}
return 0;
}
static void altera_uart_console_putc(struct console *co, const char c)
{
struct uart_port *port = &(altera_uart_ports + co->index)->port;
int i;
for (i = 0; i < 0x10000; i++) {
if (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK)
break;
}
writel(c, port->membase + ALTERA_UART_TXDATA_REG);
for (i = 0; i < 0x10000; i++) {
if (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK)
break;
}
}
static void altera_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
for (; count; count--, s++) {
altera_uart_console_putc(co, *s);
if (*s == '\n')
altera_uart_console_putc(co, '\r');
}
}
static int __init altera_uart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
return -EINVAL;
port = &altera_uart_ports[co->index].port;
if (port->membase == 0)
return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver altera_uart_driver;
static struct console altera_uart_console = {
.name = "ttyS",
.write = altera_uart_console_write,
.device = uart_console_device,
.setup = altera_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &altera_uart_driver,
};
static int __init altera_uart_console_init(void)
{
register_console(&altera_uart_console);
return 0;
}
console_initcall(altera_uart_console_init);
#define ALTERA_UART_CONSOLE (&altera_uart_console)
#else
#define ALTERA_UART_CONSOLE NULL
#endif /* CONFIG_ALTERA_UART_CONSOLE */
/*
* Define the altera_uart UART driver structure.
*/
static struct uart_driver altera_uart_driver = {
.owner = THIS_MODULE,
.driver_name = DRV_NAME,
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
.cons = ALTERA_UART_CONSOLE,
};
static int __devinit altera_uart_probe(struct platform_device *pdev)
{
struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
struct uart_port *port;
int i;
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_uart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_UART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = platp[i].uartclk;
port->ops = &altera_uart_ops;
port->flags = ASYNC_BOOT_AUTOCONF;
uart_add_one_port(&altera_uart_driver, port);
}
return 0;
}
static int altera_uart_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS; i++) {
port = &altera_uart_ports[i].port;
if (port)
uart_remove_one_port(&altera_uart_driver, port);
}
return 0;
}
static struct platform_driver altera_uart_platform_driver = {
.probe = altera_uart_probe,
.remove = __devexit_p(altera_uart_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = NULL,
},
};
static int __init altera_uart_init(void)
{
int rc;
rc = uart_register_driver(&altera_uart_driver);
if (rc)
return rc;
rc = platform_driver_register(&altera_uart_platform_driver);
if (rc) {
uart_unregister_driver(&altera_uart_driver);
return rc;
}
return 0;
}
static void __exit altera_uart_exit(void)
{
platform_driver_unregister(&altera_uart_platform_driver);
uart_unregister_driver(&altera_uart_driver);
}
module_init(altera_uart_init);
module_exit(altera_uart_exit);
MODULE_DESCRIPTION("Altera UART driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -34,32 +34,12 @@
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <asm/bfin_sport.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/portmux.h> #include <asm/portmux.h>
#include "bfin_sport_uart.h" #include "bfin_sport_uart.h"
#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
unsigned short bfin_uart_pin_req_sport0[] =
{P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0};
#endif
#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
unsigned short bfin_uart_pin_req_sport1[] =
{P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0};
#endif
#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
unsigned short bfin_uart_pin_req_sport2[] =
{P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS, \
P_SPORT2_DRPRI, P_SPORT2_RSCLK, P_SPORT2_DRSEC, P_SPORT2_DTSEC, 0};
#endif
#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
unsigned short bfin_uart_pin_req_sport3[] =
{P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS, \
P_SPORT3_DRPRI, P_SPORT3_RSCLK, P_SPORT3_DRSEC, P_SPORT3_DTSEC, 0};
#endif
struct sport_uart_port { struct sport_uart_port {
struct uart_port port; struct uart_port port;
int err_irq; int err_irq;
@ -69,9 +49,13 @@ struct sport_uart_port {
unsigned short txmask2; unsigned short txmask2;
unsigned char stopb; unsigned char stopb;
/* unsigned char parib; */ /* unsigned char parib; */
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
int cts_pin;
int rts_pin;
#endif
}; };
static void sport_uart_tx_chars(struct sport_uart_port *up); static int sport_uart_tx_chars(struct sport_uart_port *up);
static void sport_stop_tx(struct uart_port *port); static void sport_stop_tx(struct uart_port *port);
static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
@ -219,6 +203,59 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
static unsigned int sport_get_mctrl(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
if (up->cts_pin < 0)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
/* CTS PIN is negative assertive. */
if (SPORT_UART_GET_CTS(up))
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
else
return TIOCM_DSR | TIOCM_CAR;
}
static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
if (up->rts_pin < 0)
return;
/* RTS PIN is negative assertive. */
if (mctrl & TIOCM_RTS)
SPORT_UART_ENABLE_RTS(up);
else
SPORT_UART_DISABLE_RTS(up);
}
/*
* Handle any change of modem status signal.
*/
static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id)
{
struct sport_uart_port *up = (struct sport_uart_port *)dev_id;
unsigned int status;
status = sport_get_mctrl(&up->port);
uart_handle_cts_change(&up->port, status & TIOCM_CTS);
return IRQ_HANDLED;
}
#else
static unsigned int sport_get_mctrl(struct uart_port *port)
{
pr_debug("%s enter\n", __func__);
return TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
}
static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
pr_debug("%s enter\n", __func__);
}
#endif
/* Reqeust IRQ, Setup clock */ /* Reqeust IRQ, Setup clock */
static int sport_startup(struct uart_port *port) static int sport_startup(struct uart_port *port)
{ {
@ -247,6 +284,21 @@ static int sport_startup(struct uart_port *port)
goto fail2; goto fail2;
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
if (up->cts_pin >= 0) {
if (request_irq(gpio_to_irq(up->cts_pin),
sport_mctrl_cts_int,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
up->cts_pin = -1;
dev_info(port->dev, "Unable to attach BlackFin UART \
over SPORT CTS interrupt. So, disable it.\n");
}
}
if (up->rts_pin >= 0)
gpio_direction_output(up->rts_pin, 0);
#endif
return 0; return 0;
fail2: fail2:
free_irq(up->port.irq+1, up); free_irq(up->port.irq+1, up);
@ -256,23 +308,35 @@ static int sport_startup(struct uart_port *port)
return ret; return ret;
} }
static void sport_uart_tx_chars(struct sport_uart_port *up) /*
* sport_uart_tx_chars
*
* ret 1 means need to enable sport.
* ret 0 means do nothing.
*/
static int sport_uart_tx_chars(struct sport_uart_port *up)
{ {
struct circ_buf *xmit = &up->port.state->xmit; struct circ_buf *xmit = &up->port.state->xmit;
if (SPORT_GET_STAT(up) & TXF) if (SPORT_GET_STAT(up) & TXF)
return; return 0;
if (up->port.x_char) { if (up->port.x_char) {
tx_one_byte(up, up->port.x_char); tx_one_byte(up, up->port.x_char);
up->port.icount.tx++; up->port.icount.tx++;
up->port.x_char = 0; up->port.x_char = 0;
return; return 1;
} }
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
sport_stop_tx(&up->port); /* The waiting loop to stop SPORT TX from TX interrupt is
return; * too long. This may block SPORT RX interrupts and cause
* RX FIFO overflow. So, do stop sport TX only after the last
* char in TX FIFO is moved into the shift register.
*/
if (SPORT_GET_STAT(up) & TXHRE)
sport_stop_tx(&up->port);
return 0;
} }
while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) { while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
@ -283,6 +347,8 @@ static void sport_uart_tx_chars(struct sport_uart_port *up)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port); uart_write_wakeup(&up->port);
return 1;
} }
static unsigned int sport_tx_empty(struct uart_port *port) static unsigned int sport_tx_empty(struct uart_port *port)
@ -298,23 +364,15 @@ static unsigned int sport_tx_empty(struct uart_port *port)
return 0; return 0;
} }
static unsigned int sport_get_mctrl(struct uart_port *port)
{
pr_debug("%s enter\n", __func__);
return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
}
static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
pr_debug("%s enter\n", __func__);
}
static void sport_stop_tx(struct uart_port *port) static void sport_stop_tx(struct uart_port *port)
{ {
struct sport_uart_port *up = (struct sport_uart_port *)port; struct sport_uart_port *up = (struct sport_uart_port *)port;
pr_debug("%s enter\n", __func__); pr_debug("%s enter\n", __func__);
if (!(SPORT_GET_TCR1(up) & TSPEN))
return;
/* Although the hold register is empty, last byte is still in shift /* Although the hold register is empty, last byte is still in shift
* register and not sent out yet. So, put a dummy data into TX FIFO. * register and not sent out yet. So, put a dummy data into TX FIFO.
* Then, sport tx stops when last byte is shift out and the dummy * Then, sport tx stops when last byte is shift out and the dummy
@ -337,11 +395,12 @@ static void sport_start_tx(struct uart_port *port)
pr_debug("%s enter\n", __func__); pr_debug("%s enter\n", __func__);
/* Write data into SPORT FIFO before enable SPROT to transmit */ /* Write data into SPORT FIFO before enable SPROT to transmit */
sport_uart_tx_chars(up); if (sport_uart_tx_chars(up)) {
/* Enable transmit, then an interrupt will generated */
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
SSYNC();
}
/* Enable transmit, then an interrupt will generated */
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
SSYNC();
pr_debug("%s exit\n", __func__); pr_debug("%s exit\n", __func__);
} }
@ -379,6 +438,10 @@ static void sport_shutdown(struct uart_port *port)
free_irq(up->port.irq, up); free_irq(up->port.irq, up);
free_irq(up->port.irq+1, up); free_irq(up->port.irq+1, up);
free_irq(up->err_irq, up); free_irq(up->err_irq, up);
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
if (up->cts_pin >= 0)
free_irq(gpio_to_irq(up->cts_pin), up);
#endif
} }
static const char *sport_type(struct uart_port *port) static const char *sport_type(struct uart_port *port)
@ -448,27 +511,14 @@ static void sport_set_termios(struct uart_port *port,
/* up->parib = 1; */ /* up->parib = 1; */
} }
port->read_status_mask = OE; spin_lock_irqsave(&up->port.lock, flags);
if (termios->c_iflag & INPCK)
port->read_status_mask |= (FE | PE); port->read_status_mask = 0;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= BI;
/* /*
* Characters to ignore * Characters to ignore
*/ */
port->ignore_status_mask = 0; port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= FE | PE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= BI;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= OE;
}
/* RX extract mask */ /* RX extract mask */
up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8); up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8);
@ -488,8 +538,6 @@ static void sport_set_termios(struct uart_port *port,
/* uart baud rate */ /* uart baud rate */
port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16); port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
spin_lock_irqsave(&up->port.lock, flags);
/* Disable UART */ /* Disable UART */
SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN); SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
@ -542,6 +590,8 @@ struct uart_ops sport_uart_ops = {
static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS]; static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS];
#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
#define CLASS_BFIN_SPORT_CONSOLE "bfin-sport-console"
static int __init static int __init
sport_uart_console_setup(struct console *co, char *options) sport_uart_console_setup(struct console *co, char *options)
{ {
@ -549,7 +599,11 @@ sport_uart_console_setup(struct console *co, char *options)
int baud = 57600; int baud = 57600;
int bits = 8; int bits = 8;
int parity = 'n'; int parity = 'n';
# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
int flow = 'r';
# else
int flow = 'n'; int flow = 'n';
# endif
/* Check whether an invalid uart number has been specified */ /* Check whether an invalid uart number has been specified */
if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS) if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
@ -690,11 +744,11 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
if (bfin_sport_uart_ports[pdev->id] == NULL) { if (bfin_sport_uart_ports[pdev->id] == NULL) {
bfin_sport_uart_ports[pdev->id] = bfin_sport_uart_ports[pdev->id] =
kmalloc(sizeof(struct sport_uart_port), GFP_KERNEL); kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
sport = bfin_sport_uart_ports[pdev->id]; sport = bfin_sport_uart_ports[pdev->id];
if (!sport) { if (!sport) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Fail to kmalloc sport_uart_port\n"); "Fail to malloc sport_uart_port\n");
return -ENOMEM; return -ENOMEM;
} }
@ -720,13 +774,13 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
goto out_error_free_peripherals; goto out_error_free_peripherals;
} }
sport->port.membase = ioremap(res->start, sport->port.membase = ioremap(res->start, resource_size(res));
res->end - res->start);
if (!sport->port.membase) { if (!sport->port.membase) {
dev_err(&pdev->dev, "Cannot map sport IO\n"); dev_err(&pdev->dev, "Cannot map sport IO\n");
ret = -ENXIO; ret = -ENXIO;
goto out_error_free_peripherals; goto out_error_free_peripherals;
} }
sport->port.mapbase = res->start;
sport->port.irq = platform_get_irq(pdev, 0); sport->port.irq = platform_get_irq(pdev, 0);
if (sport->port.irq < 0) { if (sport->port.irq < 0) {
@ -741,6 +795,22 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
ret = -ENOENT; ret = -ENOENT;
goto out_error_unmap; goto out_error_unmap;
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL)
sport->cts_pin = -1;
else
sport->cts_pin = res->start;
res = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (res == NULL)
sport->rts_pin = -1;
else
sport->rts_pin = res->start;
if (sport->rts_pin >= 0)
gpio_request(sport->rts_pin, DRV_NAME);
#endif
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
@ -779,6 +849,10 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
if (sport) { if (sport) {
uart_remove_one_port(&sport_uart_reg, &sport->port); uart_remove_one_port(&sport_uart_reg, &sport->port);
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (sport->rts_pin >= 0)
gpio_free(sport->rts_pin);
#endif
iounmap(sport->port.membase); iounmap(sport->port.membase);
peripheral_free_list( peripheral_free_list(
(unsigned short *)pdev->dev.platform_data); (unsigned short *)pdev->dev.platform_data);
@ -802,7 +876,7 @@ static struct platform_driver sport_uart_driver = {
#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
static __initdata struct early_platform_driver early_sport_uart_driver = { static __initdata struct early_platform_driver early_sport_uart_driver = {
.class_str = DRV_NAME, .class_str = CLASS_BFIN_SPORT_CONSOLE,
.pdrv = &sport_uart_driver, .pdrv = &sport_uart_driver,
.requested_id = EARLY_PLATFORM_ID_UNSET, .requested_id = EARLY_PLATFORM_ID_UNSET,
}; };
@ -811,7 +885,8 @@ static int __init sport_uart_rs_console_init(void)
{ {
early_platform_driver_register(&early_sport_uart_driver, DRV_NAME); early_platform_driver_register(&early_sport_uart_driver, DRV_NAME);
early_platform_driver_probe(DRV_NAME, BFIN_SPORT_UART_MAX_PORTS, 0); early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE,
BFIN_SPORT_UART_MAX_PORTS, 0);
register_console(&sport_uart_console); register_console(&sport_uart_console);
@ -824,7 +899,7 @@ static int __init sport_uart_init(void)
{ {
int ret; int ret;
pr_info("Serial: Blackfin uart over sport driver\n"); pr_info("Blackfin uart over sport driver\n");
ret = uart_register_driver(&sport_uart_reg); ret = uart_register_driver(&sport_uart_reg);
if (ret) { if (ret) {

View File

@ -37,7 +37,21 @@
#define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV)) #define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
#define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX)) #define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX))
#define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX)) #define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX))
#define SPORT_GET_RX32(sport) bfin_read32(((sport)->port.membase + OFFSET_RX)) /*
* If another interrupt fires while doing a 32-bit read from RX FIFO,
* a fake RX underflow error will be generated. So disable interrupts
* to prevent interruption while reading the FIFO.
*/
#define SPORT_GET_RX32(sport) \
({ \
unsigned int __ret; \
if (ANOMALY_05000473) \
local_irq_disable(); \
__ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
if (ANOMALY_05000473) \
local_irq_enable(); \
__ret; \
})
#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1)) #define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1))
#define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2)) #define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2))
#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV)) #define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
@ -58,4 +72,15 @@
#define SPORT_TX_FIFO_SIZE 8 #define SPORT_TX_FIFO_SIZE 8
#define SPORT_UART_GET_CTS(x) gpio_get_value(x->cts_pin)
#define SPORT_UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
#define SPORT_UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \
|| defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \
|| defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \
|| defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS)
# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS
#endif
#endif /* _BFIN_SPORT_UART_H */ #endif /* _BFIN_SPORT_UART_H */

View File

@ -68,12 +68,22 @@ static void timbuart_start_tx(struct uart_port *port)
tasklet_schedule(&uart->tasklet); tasklet_schedule(&uart->tasklet);
} }
static unsigned int timbuart_tx_empty(struct uart_port *port)
{
u32 isr = ioread32(port->membase + TIMBUART_ISR);
return (isr & TXBE) ? TIOCSER_TEMT : 0;
}
static void timbuart_flush_buffer(struct uart_port *port) static void timbuart_flush_buffer(struct uart_port *port)
{ {
u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX; if (!timbuart_tx_empty(port)) {
u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
TIMBUART_CTRL_FLSHTX;
iowrite8(ctl, port->membase + TIMBUART_CTRL); iowrite8(ctl, port->membase + TIMBUART_CTRL);
iowrite32(TXBF, port->membase + TIMBUART_ISR); iowrite32(TXBF, port->membase + TIMBUART_ISR);
}
} }
static void timbuart_rx_chars(struct uart_port *port) static void timbuart_rx_chars(struct uart_port *port)
@ -195,13 +205,6 @@ void timbuart_tasklet(unsigned long arg)
dev_dbg(uart->port.dev, "%s leaving\n", __func__); dev_dbg(uart->port.dev, "%s leaving\n", __func__);
} }
static unsigned int timbuart_tx_empty(struct uart_port *port)
{
u32 isr = ioread32(port->membase + TIMBUART_ISR);
return (isr & TXBE) ? TIOCSER_TEMT : 0;
}
static unsigned int timbuart_get_mctrl(struct uart_port *port) static unsigned int timbuart_get_mctrl(struct uart_port *port)
{ {
u8 cts = ioread8(port->membase + TIMBUART_CTRL); u8 cts = ioread8(port->membase + TIMBUART_CTRL);
@ -220,7 +223,7 @@ static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_RTS) if (mctrl & TIOCM_RTS)
iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
else else
iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); iowrite8(0, port->membase + TIMBUART_CTRL);
} }
static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier) static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)

View File

@ -86,7 +86,7 @@ static int ulite_receive(struct uart_port *port, int stat)
/* stats */ /* stats */
if (stat & ULITE_STATUS_RXVALID) { if (stat & ULITE_STATUS_RXVALID) {
port->icount.rx++; port->icount.rx++;
ch = readb(port->membase + ULITE_RX); ch = ioread32be(port->membase + ULITE_RX);
if (stat & ULITE_STATUS_PARITY) if (stat & ULITE_STATUS_PARITY)
port->icount.parity++; port->icount.parity++;
@ -131,7 +131,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
return 0; return 0;
if (port->x_char) { if (port->x_char) {
writeb(port->x_char, port->membase + ULITE_TX); iowrite32be(port->x_char, port->membase + ULITE_TX);
port->x_char = 0; port->x_char = 0;
port->icount.tx++; port->icount.tx++;
return 1; return 1;
@ -140,7 +140,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return 0; return 0;
writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX); iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
port->icount.tx++; port->icount.tx++;
@ -157,7 +157,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
int busy, n = 0; int busy, n = 0;
do { do {
int stat = readb(port->membase + ULITE_STATUS); int stat = ioread32be(port->membase + ULITE_STATUS);
busy = ulite_receive(port, stat); busy = ulite_receive(port, stat);
busy |= ulite_transmit(port, stat); busy |= ulite_transmit(port, stat);
n++; n++;
@ -178,7 +178,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port)
unsigned int ret; unsigned int ret;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
ret = readb(port->membase + ULITE_STATUS); ret = ioread32be(port->membase + ULITE_STATUS);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
@ -201,7 +201,7 @@ static void ulite_stop_tx(struct uart_port *port)
static void ulite_start_tx(struct uart_port *port) static void ulite_start_tx(struct uart_port *port)
{ {
ulite_transmit(port, readb(port->membase + ULITE_STATUS)); ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS));
} }
static void ulite_stop_rx(struct uart_port *port) static void ulite_stop_rx(struct uart_port *port)
@ -230,17 +230,17 @@ static int ulite_startup(struct uart_port *port)
if (ret) if (ret)
return ret; return ret;
writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
port->membase + ULITE_CONTROL); port->membase + ULITE_CONTROL);
writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
return 0; return 0;
} }
static void ulite_shutdown(struct uart_port *port) static void ulite_shutdown(struct uart_port *port)
{ {
writeb(0, port->membase + ULITE_CONTROL); iowrite32be(0, port->membase + ULITE_CONTROL);
readb(port->membase + ULITE_CONTROL); /* dummy */ ioread32be(port->membase + ULITE_CONTROL); /* dummy */
free_irq(port->irq, port); free_irq(port->irq, port);
} }
@ -352,7 +352,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
/* Spin waiting for TX fifo to have space available */ /* Spin waiting for TX fifo to have space available */
for (i = 0; i < 100000; i++) { for (i = 0; i < 100000; i++) {
val = readb(port->membase + ULITE_STATUS); val = ioread32be(port->membase + ULITE_STATUS);
if ((val & ULITE_STATUS_TXFULL) == 0) if ((val & ULITE_STATUS_TXFULL) == 0)
break; break;
cpu_relax(); cpu_relax();
@ -362,7 +362,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
static void ulite_console_putchar(struct uart_port *port, int ch) static void ulite_console_putchar(struct uart_port *port, int ch)
{ {
ulite_console_wait_tx(port); ulite_console_wait_tx(port);
writeb(ch, port->membase + ULITE_TX); iowrite32be(ch, port->membase + ULITE_TX);
} }
static void ulite_console_write(struct console *co, const char *s, static void ulite_console_write(struct console *co, const char *s,
@ -379,8 +379,8 @@ static void ulite_console_write(struct console *co, const char *s,
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
/* save and disable interrupt */ /* save and disable interrupt */
ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
writeb(0, port->membase + ULITE_CONTROL); iowrite32be(0, port->membase + ULITE_CONTROL);
uart_console_write(port, s, count, ulite_console_putchar); uart_console_write(port, s, count, ulite_console_putchar);
@ -388,7 +388,7 @@ static void ulite_console_write(struct console *co, const char *s,
/* restore interrupt state */ /* restore interrupt state */
if (ier) if (ier)
writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
if (locked) if (locked)
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
@ -601,7 +601,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match)
id = of_get_property(op->node, "port-number", NULL); id = of_get_property(op->node, "port-number", NULL);
return ulite_assign(&op->dev, id ? *id : -1, res.start+3, irq); return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
} }
static int __devexit ulite_of_remove(struct of_device *op) static int __devexit ulite_of_remove(struct of_device *op)

View File

@ -0,0 +1,16 @@
/*
* altera_jtaguart.h -- Altera JTAG UART driver defines.
*/
#ifndef __ALTJUART_H
#define __ALTJUART_H
#define ALTERA_JTAGUART_MAJOR 204
#define ALTERA_JTAGUART_MINOR 186
struct altera_jtaguart_platform_uart {
unsigned long mapbase; /* Physical address base */
unsigned int irq; /* Interrupt vector */
};
#endif /* __ALTJUART_H */

View File

@ -0,0 +1,14 @@
/*
* altera_uart.h -- Altera UART driver defines.
*/
#ifndef __ALTUART_H
#define __ALTUART_H
struct altera_uart_platform_uart {
unsigned long mapbase; /* Physical address base */
unsigned int irq; /* Interrupt vector */
unsigned int uartclk; /* UART clock rate */
};
#endif /* __ALTUART_H */

25
include/linux/gsmmux.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _LINUX_GSMMUX_H
#define _LINUX_GSMMUX_H
struct gsm_config
{
unsigned int adaption;
unsigned int encapsulation;
unsigned int initiator;
unsigned int t1;
unsigned int t2;
unsigned int t3;
unsigned int n2;
unsigned int mru;
unsigned int mtu;
unsigned int k;
unsigned int i;
unsigned int unused[8]; /* Padding for expansion without
breaking stuff */
};
#define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config)
#define GSMIOC_SETCONF _IOW('G', 1, struct gsm_config)
#endif

View File

@ -182,6 +182,10 @@
/* Aeroflex Gaisler GRLIB APBUART */ /* Aeroflex Gaisler GRLIB APBUART */
#define PORT_APBUART 90 #define PORT_APBUART 90
/* Altera UARTs */
#define PORT_ALTERA_JTAGUART 91
#define PORT_ALTERA_UART 92
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/compiler.h> #include <linux/compiler.h>

View File

@ -23,7 +23,7 @@
*/ */
#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
#define NR_LDISCS 21 #define NR_LDISCS 30
/* line disciplines */ /* line disciplines */
#define N_TTY 0 #define N_TTY 0
@ -48,6 +48,7 @@
#define N_PPS 18 /* Pulse per Second */ #define N_PPS 18 /* Pulse per Second */
#define N_V253 19 /* Codec control over voice modem */ #define N_V253 19 /* Codec control over voice modem */
#define N_CAIF 20 /* CAIF protocol for talking to modems */ #define N_CAIF 20 /* CAIF protocol for talking to modems */
#define N_GSM0710 21 /* GSM 0710 Mux */
/* /*
* This character is the same as _POSIX_VDISABLE: it cannot be used as * This character is the same as _POSIX_VDISABLE: it cannot be used as