mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Merge remote branch 'origin' into secretlab/next-spi
This commit is contained in:
commit
b1e50ebcf2
6890 changed files with 470191 additions and 215018 deletions
|
|
@ -1891,8 +1891,8 @@ static int serial8250_get_poll_char(struct uart_port *port)
|
|||
struct uart_8250_port *up = (struct uart_8250_port *)port;
|
||||
unsigned char lsr = serial_inp(up, UART_LSR);
|
||||
|
||||
while (!(lsr & UART_LSR_DR))
|
||||
lsr = serial_inp(up, UART_LSR);
|
||||
if (!(lsr & UART_LSR_DR))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return serial_inp(up, UART_RX);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -518,12 +518,13 @@ config SERIAL_S3C2412
|
|||
Serial port support for the Samsung S3C2412 and S3C2413 SoC
|
||||
|
||||
config SERIAL_S3C2440
|
||||
tristate "Samsung S3C2440/S3C2442 Serial port support"
|
||||
depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442)
|
||||
tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support"
|
||||
depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416)
|
||||
default y if CPU_S3C2440
|
||||
default y if CPU_S3C2442
|
||||
select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416
|
||||
help
|
||||
Serial port support for the Samsung S3C2440 and S3C2442 SoC
|
||||
Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC
|
||||
|
||||
config SERIAL_S3C24A0
|
||||
tristate "Samsung S3C24A0 Serial port support"
|
||||
|
|
@ -533,21 +534,13 @@ config SERIAL_S3C24A0
|
|||
Serial port support for the Samsung S3C24A0 SoC
|
||||
|
||||
config SERIAL_S3C6400
|
||||
tristate "Samsung S3C6400/S3C6410/S5P6440 Seria port support"
|
||||
depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440)
|
||||
tristate "Samsung S3C6400/S3C6410/S5P6440/S5PC100 Serial port support"
|
||||
depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5PC100)
|
||||
select SERIAL_SAMSUNG_UARTS_4
|
||||
default y
|
||||
help
|
||||
Serial port support for the Samsung S3C6400, S3C6410 and S5P6440
|
||||
SoCs
|
||||
|
||||
config SERIAL_S5PC100
|
||||
tristate "Samsung S5PC100 Serial port support"
|
||||
depends on SERIAL_SAMSUNG && CPU_S5PC100
|
||||
select SERIAL_SAMSUNG_UARTS_4
|
||||
default y
|
||||
help
|
||||
Serial port support for the Samsung S5PC100 SoCs
|
||||
Serial port support for the Samsung S3C6400, S3C6410, S5P6440
|
||||
and S5PC100 SoCs
|
||||
|
||||
config SERIAL_S5PV210
|
||||
tristate "Samsung S5PV210 Serial port support"
|
||||
|
|
@ -1430,8 +1423,8 @@ config SERIAL_SC26XX_CONSOLE
|
|||
Support for Console on SC2681/SC2692 serial ports.
|
||||
|
||||
config SERIAL_BFIN_SPORT
|
||||
tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)"
|
||||
depends on BLACKFIN && EXPERIMENTAL
|
||||
tristate "Blackfin SPORT emulate UART"
|
||||
depends on BLACKFIN
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Enable SPORT emulate UART on Blackfin series.
|
||||
|
|
@ -1446,28 +1439,52 @@ config SERIAL_BFIN_SPORT_CONSOLE
|
|||
|
||||
config SERIAL_BFIN_SPORT0_UART
|
||||
bool "Enable UART over SPORT0"
|
||||
depends on SERIAL_BFIN_SPORT && !(BF542 || BF542M || BF544 || BF544M)
|
||||
depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
|
||||
help
|
||||
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
|
||||
bool "Enable UART over SPORT1"
|
||||
depends on SERIAL_BFIN_SPORT
|
||||
help
|
||||
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
|
||||
bool "Enable UART over SPORT2"
|
||||
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
|
||||
help
|
||||
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
|
||||
bool "Enable UART over SPORT3"
|
||||
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
|
||||
help
|
||||
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
|
||||
tristate "Support for timberdale UART"
|
||||
select SERIAL_CORE
|
||||
|
|
@ -1506,4 +1523,56 @@ config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
|
|||
help
|
||||
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
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
|
|||
obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
|
||||
obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
|
||||
obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
|
||||
obj-$(CONFIG_SERIAL_S5PC100) += s3c6400.o
|
||||
obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
|
||||
obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
|
||||
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
|
||||
|
|
@ -83,3 +82,5 @@ obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
|
|||
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
|
||||
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.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
|
||||
|
|
|
|||
504
drivers/serial/altera_jtaguart.c
Normal file
504
drivers/serial/altera_jtaguart.c
Normal 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 <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
570
drivers/serial/altera_uart.c
Normal file
570
drivers/serial/altera_uart.c
Normal 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 <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
|
@ -342,9 +342,9 @@ static int pl010_get_poll_char(struct uart_port *port)
|
|||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
unsigned int status;
|
||||
|
||||
do {
|
||||
status = readw(uap->port.membase + UART01x_FR);
|
||||
} while (status & UART01x_FR_RXFE);
|
||||
status = readw(uap->port.membase + UART01x_FR);
|
||||
if (status & UART01x_FR_RXFE)
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return readw(uap->port.membase + UART01x_DR);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -559,7 +559,7 @@ static int __devinit apbuart_probe(struct of_device *op,
|
|||
|
||||
i = 0;
|
||||
for (i = 0; i < grlib_apbuart_port_nr; i++) {
|
||||
if (op->node == grlib_apbuart_nodes[i])
|
||||
if (op->dev.of_node == grlib_apbuart_nodes[i])
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -584,12 +584,12 @@ static struct of_device_id __initdata apbuart_match[] = {
|
|||
};
|
||||
|
||||
static struct of_platform_driver grlib_apbuart_of_driver = {
|
||||
.match_table = apbuart_match,
|
||||
.probe = apbuart_probe,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "grlib-apbuart",
|
||||
},
|
||||
.owner = THIS_MODULE,
|
||||
.name = "grlib-apbuart",
|
||||
.of_match_table = apbuart_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/atmel_pdc.h>
|
||||
#include <linux/atmel_serial.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
|
|
@ -59,6 +60,9 @@
|
|||
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
static void atmel_start_rx(struct uart_port *port);
|
||||
static void atmel_stop_rx(struct uart_port *port);
|
||||
|
||||
#ifdef CONFIG_SERIAL_ATMEL_TTYAT
|
||||
|
||||
/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we
|
||||
|
|
@ -93,6 +97,7 @@
|
|||
#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR)
|
||||
#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
|
||||
#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
|
||||
#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
|
||||
|
||||
/* PDC registers */
|
||||
#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
|
||||
|
|
@ -147,6 +152,9 @@ struct atmel_uart_port {
|
|||
unsigned int irq_status_prev;
|
||||
|
||||
struct circ_buf rx_ring;
|
||||
|
||||
struct serial_rs485 rs485; /* rs485 settings */
|
||||
unsigned int tx_done_mask;
|
||||
};
|
||||
|
||||
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
|
||||
|
|
@ -187,6 +195,46 @@ static bool atmel_use_dma_tx(struct uart_port *port)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Enable or disable the rs485 support */
|
||||
void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int mode;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
/* Disable interrupts */
|
||||
UART_PUT_IDR(port, atmel_port->tx_done_mask);
|
||||
|
||||
mode = UART_GET_MR(port);
|
||||
|
||||
/* Resetting serial mode to RS232 (0x0) */
|
||||
mode &= ~ATMEL_US_USMODE;
|
||||
|
||||
atmel_port->rs485 = *rs485conf;
|
||||
|
||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
|
||||
UART_PUT_TTGR(port, rs485conf->delay_rts_before_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else {
|
||||
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||
if (atmel_use_dma_tx(port))
|
||||
atmel_port->tx_done_mask = ATMEL_US_ENDTX |
|
||||
ATMEL_US_TXBUFE;
|
||||
else
|
||||
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
|
||||
}
|
||||
UART_PUT_MR(port, mode);
|
||||
|
||||
/* Enable interrupts */
|
||||
UART_PUT_IER(port, atmel_port->tx_done_mask);
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
|
||||
*/
|
||||
|
|
@ -202,6 +250,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
|||
{
|
||||
unsigned int control = 0;
|
||||
unsigned int mode;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
#ifdef CONFIG_ARCH_AT91RM9200
|
||||
if (cpu_is_at91rm9200()) {
|
||||
|
|
@ -236,6 +285,17 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
|||
mode |= ATMEL_US_CHMODE_LOC_LOOP;
|
||||
else
|
||||
mode |= ATMEL_US_CHMODE_NORMAL;
|
||||
|
||||
/* Resetting serial mode to RS232 (0x0) */
|
||||
mode &= ~ATMEL_US_USMODE;
|
||||
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
UART_PUT_TTGR(port, atmel_port->rs485.delay_rts_before_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else {
|
||||
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||
}
|
||||
UART_PUT_MR(port, mode);
|
||||
}
|
||||
|
||||
|
|
@ -268,12 +328,17 @@ static u_int atmel_get_mctrl(struct uart_port *port)
|
|||
*/
|
||||
static void atmel_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (atmel_use_dma_tx(port)) {
|
||||
/* disable PDC transmit */
|
||||
UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
|
||||
UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
|
||||
} else
|
||||
UART_PUT_IDR(port, ATMEL_US_TXRDY);
|
||||
}
|
||||
/* Disable interrupts */
|
||||
UART_PUT_IDR(port, atmel_port->tx_done_mask);
|
||||
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -281,17 +346,39 @@ static void atmel_stop_tx(struct uart_port *port)
|
|||
*/
|
||||
static void atmel_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (atmel_use_dma_tx(port)) {
|
||||
if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
|
||||
/* The transmitter is already running. Yes, we
|
||||
really need this.*/
|
||||
return;
|
||||
|
||||
UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
|
||||
atmel_stop_rx(port);
|
||||
|
||||
/* re-enable PDC transmit */
|
||||
UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
|
||||
} else
|
||||
UART_PUT_IER(port, ATMEL_US_TXRDY);
|
||||
}
|
||||
/* Enable interrupts */
|
||||
UART_PUT_IER(port, atmel_port->tx_done_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* start receiving - port is in process of being opened.
|
||||
*/
|
||||
static void atmel_start_rx(struct uart_port *port)
|
||||
{
|
||||
UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */
|
||||
|
||||
if (atmel_use_dma_rx(port)) {
|
||||
/* enable PDC controller */
|
||||
UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
|
||||
port->read_status_mask);
|
||||
UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
|
||||
} else {
|
||||
UART_PUT_IER(port, ATMEL_US_RXRDY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -302,9 +389,11 @@ static void atmel_stop_rx(struct uart_port *port)
|
|||
if (atmel_use_dma_rx(port)) {
|
||||
/* disable PDC receive */
|
||||
UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
|
||||
UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
|
||||
} else
|
||||
UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
|
||||
port->read_status_mask);
|
||||
} else {
|
||||
UART_PUT_IDR(port, ATMEL_US_RXRDY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -428,8 +517,9 @@ static void atmel_rx_chars(struct uart_port *port)
|
|||
static void atmel_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) {
|
||||
if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) {
|
||||
UART_PUT_CHAR(port, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
|
|
@ -437,7 +527,7 @@ static void atmel_tx_chars(struct uart_port *port)
|
|||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
|
||||
while (UART_GET_CSR(port) & atmel_port->tx_done_mask) {
|
||||
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
|
|
@ -449,7 +539,8 @@ static void atmel_tx_chars(struct uart_port *port)
|
|||
uart_write_wakeup(port);
|
||||
|
||||
if (!uart_circ_empty(xmit))
|
||||
UART_PUT_IER(port, ATMEL_US_TXRDY);
|
||||
/* Enable interrupts */
|
||||
UART_PUT_IER(port, atmel_port->tx_done_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -501,18 +592,10 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending)
|
|||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (atmel_use_dma_tx(port)) {
|
||||
/* PDC transmit */
|
||||
if (pending & (ATMEL_US_ENDTX | ATMEL_US_TXBUFE)) {
|
||||
UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
}
|
||||
} else {
|
||||
/* Interrupt transmit */
|
||||
if (pending & ATMEL_US_TXRDY) {
|
||||
UART_PUT_IDR(port, ATMEL_US_TXRDY);
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
}
|
||||
if (pending & atmel_port->tx_done_mask) {
|
||||
/* Either PDC or interrupt transmission */
|
||||
UART_PUT_IDR(port, atmel_port->tx_done_mask);
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -590,9 +673,15 @@ static void atmel_tx_dma(struct uart_port *port)
|
|||
|
||||
UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
|
||||
UART_PUT_TCR(port, count);
|
||||
/* re-enable PDC transmit and interrupts */
|
||||
/* re-enable PDC transmit */
|
||||
UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
|
||||
UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
|
||||
/* Enable interrupts */
|
||||
UART_PUT_IER(port, atmel_port->tx_done_mask);
|
||||
} else {
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* DMA done, stop TX, start RX for RS485 */
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
|
@ -1017,6 +1106,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
{
|
||||
unsigned long flags;
|
||||
unsigned int mode, imr, quot, baud;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
/* Get current mode register */
|
||||
mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
|
||||
|
|
@ -1115,6 +1205,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
/* disable receiver and transmitter */
|
||||
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
|
||||
|
||||
/* Resetting serial mode to RS232 (0x0) */
|
||||
mode &= ~ATMEL_US_USMODE;
|
||||
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
UART_PUT_TTGR(port, atmel_port->rs485.delay_rts_before_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else {
|
||||
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||
}
|
||||
|
||||
/* set the parity, stop bits and data size */
|
||||
UART_PUT_MR(port, mode);
|
||||
|
||||
|
|
@ -1231,6 +1332,35 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct serial_rs485 rs485conf;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
|
||||
atmel_config_rs485(port, &rs485conf);
|
||||
break;
|
||||
|
||||
case TIOCGRS485:
|
||||
if (copy_to_user((struct serial_rs485 *) arg,
|
||||
&(to_atmel_uart_port(port)->rs485),
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct uart_ops atmel_pops = {
|
||||
.tx_empty = atmel_tx_empty,
|
||||
.set_mctrl = atmel_set_mctrl,
|
||||
|
|
@ -1250,6 +1380,7 @@ static struct uart_ops atmel_pops = {
|
|||
.config_port = atmel_config_port,
|
||||
.verify_port = atmel_verify_port,
|
||||
.pm = atmel_serial_pm,
|
||||
.ioctl = atmel_ioctl,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = atmel_poll_get_char,
|
||||
.poll_put_char = atmel_poll_put_char,
|
||||
|
|
@ -1265,13 +1396,12 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||
struct uart_port *port = &atmel_port->uart;
|
||||
struct atmel_uart_data *data = pdev->dev.platform_data;
|
||||
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->ops = &atmel_pops;
|
||||
port->fifosize = 1;
|
||||
port->line = pdev->id;
|
||||
port->dev = &pdev->dev;
|
||||
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->ops = &atmel_pops;
|
||||
port->fifosize = 1;
|
||||
port->line = pdev->id;
|
||||
port->dev = &pdev->dev;
|
||||
port->mapbase = pdev->resource[0].start;
|
||||
port->irq = pdev->resource[1].start;
|
||||
|
||||
|
|
@ -1299,8 +1429,16 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||
|
||||
atmel_port->use_dma_rx = data->use_dma_rx;
|
||||
atmel_port->use_dma_tx = data->use_dma_tx;
|
||||
if (atmel_use_dma_tx(port))
|
||||
atmel_port->rs485 = data->rs485;
|
||||
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
|
||||
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
|
||||
else if (atmel_use_dma_tx(port)) {
|
||||
port->fifosize = PDC_BUFFER_SIZE;
|
||||
atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
|
||||
} else {
|
||||
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1334,6 +1472,7 @@ static void atmel_console_putchar(struct uart_port *port, int ch)
|
|||
static void atmel_console_write(struct console *co, const char *s, u_int count)
|
||||
{
|
||||
struct uart_port *port = &atmel_ports[co->index].uart;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int status, imr;
|
||||
unsigned int pdc_tx;
|
||||
|
||||
|
|
@ -1341,7 +1480,7 @@ static void atmel_console_write(struct console *co, const char *s, u_int count)
|
|||
* First, save IMR and then disable interrupts
|
||||
*/
|
||||
imr = UART_GET_IMR(port);
|
||||
UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
|
||||
UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
|
||||
|
||||
/* Store PDC transmit status and disable it */
|
||||
pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
|
||||
|
|
|
|||
|
|
@ -34,32 +34,12 @@
|
|||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#include <asm/bfin_sport.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/portmux.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 uart_port port;
|
||||
int err_irq;
|
||||
|
|
@ -69,9 +49,13 @@ struct sport_uart_port {
|
|||
unsigned short txmask2;
|
||||
unsigned char stopb;
|
||||
/* 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 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;
|
||||
}
|
||||
|
||||
#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 */
|
||||
static int sport_startup(struct uart_port *port)
|
||||
{
|
||||
|
|
@ -247,6 +284,21 @@ static int sport_startup(struct uart_port *port)
|
|||
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;
|
||||
fail2:
|
||||
free_irq(up->port.irq+1, up);
|
||||
|
|
@ -256,23 +308,35 @@ static int sport_startup(struct uart_port *port)
|
|||
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;
|
||||
|
||||
if (SPORT_GET_STAT(up) & TXF)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (up->port.x_char) {
|
||||
tx_one_byte(up, up->port.x_char);
|
||||
up->port.icount.tx++;
|
||||
up->port.x_char = 0;
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
|
||||
sport_stop_tx(&up->port);
|
||||
return;
|
||||
/* The waiting loop to stop SPORT TX from TX interrupt is
|
||||
* 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)) {
|
||||
|
|
@ -283,6 +347,8 @@ static void sport_uart_tx_chars(struct sport_uart_port *up)
|
|||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct sport_uart_port *up = (struct sport_uart_port *)port;
|
||||
|
||||
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
|
||||
* 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
|
||||
|
|
@ -337,11 +395,12 @@ static void sport_start_tx(struct uart_port *port)
|
|||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
/* 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__);
|
||||
}
|
||||
|
||||
|
|
@ -379,6 +438,10 @@ static void sport_shutdown(struct uart_port *port)
|
|||
free_irq(up->port.irq, up);
|
||||
free_irq(up->port.irq+1, 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)
|
||||
|
|
@ -448,27 +511,14 @@ static void sport_set_termios(struct uart_port *port,
|
|||
/* up->parib = 1; */
|
||||
}
|
||||
|
||||
port->read_status_mask = OE;
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= (FE | PE);
|
||||
if (termios->c_iflag & (BRKINT | PARMRK))
|
||||
port->read_status_mask |= BI;
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
||||
port->read_status_mask = 0;
|
||||
|
||||
/*
|
||||
* Characters to ignore
|
||||
*/
|
||||
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 */
|
||||
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 */
|
||||
port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
||||
/* Disable UART */
|
||||
SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
|
||||
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];
|
||||
|
||||
#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
|
||||
#define CLASS_BFIN_SPORT_CONSOLE "bfin-sport-console"
|
||||
|
||||
static int __init
|
||||
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 bits = 8;
|
||||
int parity = 'n';
|
||||
# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
|
||||
int flow = 'r';
|
||||
# else
|
||||
int flow = 'n';
|
||||
# endif
|
||||
|
||||
/* Check whether an invalid uart number has been specified */
|
||||
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) {
|
||||
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];
|
||||
if (!sport) {
|
||||
dev_err(&pdev->dev,
|
||||
"Fail to kmalloc sport_uart_port\n");
|
||||
"Fail to malloc sport_uart_port\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -720,13 +774,13 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
|
|||
goto out_error_free_peripherals;
|
||||
}
|
||||
|
||||
sport->port.membase = ioremap(res->start,
|
||||
res->end - res->start);
|
||||
sport->port.membase = ioremap(res->start, resource_size(res));
|
||||
if (!sport->port.membase) {
|
||||
dev_err(&pdev->dev, "Cannot map sport IO\n");
|
||||
ret = -ENXIO;
|
||||
goto out_error_free_peripherals;
|
||||
}
|
||||
sport->port.mapbase = res->start;
|
||||
|
||||
sport->port.irq = platform_get_irq(pdev, 0);
|
||||
if (sport->port.irq < 0) {
|
||||
|
|
@ -741,6 +795,22 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
|
|||
ret = -ENOENT;
|
||||
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
|
||||
|
|
@ -779,6 +849,10 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
|
|||
|
||||
if (sport) {
|
||||
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);
|
||||
peripheral_free_list(
|
||||
(unsigned short *)pdev->dev.platform_data);
|
||||
|
|
@ -802,7 +876,7 @@ static struct platform_driver sport_uart_driver = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
|
||||
static __initdata struct early_platform_driver early_sport_uart_driver = {
|
||||
.class_str = DRV_NAME,
|
||||
.class_str = CLASS_BFIN_SPORT_CONSOLE,
|
||||
.pdrv = &sport_uart_driver,
|
||||
.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_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);
|
||||
|
||||
|
|
@ -824,7 +899,7 @@ static int __init sport_uart_init(void)
|
|||
{
|
||||
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);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,21 @@
|
|||
#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_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_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2))
|
||||
#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
|
||||
|
|
@ -58,4 +72,15 @@
|
|||
|
||||
#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 */
|
||||
|
|
|
|||
|
|
@ -1342,7 +1342,7 @@ static int __devinit cpm_uart_probe(struct of_device *ofdev,
|
|||
/* initialize the device pointer for the port */
|
||||
pinfo->port.dev = &ofdev->dev;
|
||||
|
||||
ret = cpm_uart_init_port(ofdev->node, pinfo);
|
||||
ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1372,8 +1372,11 @@ static struct of_device_id cpm_uart_match[] = {
|
|||
};
|
||||
|
||||
static struct of_platform_driver cpm_uart_driver = {
|
||||
.name = "cpm_uart",
|
||||
.match_table = cpm_uart_match,
|
||||
.driver = {
|
||||
.name = "cpm_uart",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = cpm_uart_match,
|
||||
},
|
||||
.probe = cpm_uart_probe,
|
||||
.remove = cpm_uart_remove,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/kdb.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/console.h>
|
||||
|
||||
#define MAX_CONFIG_LEN 40
|
||||
|
||||
|
|
@ -32,6 +34,40 @@ static struct kparam_string kps = {
|
|||
static struct tty_driver *kgdb_tty_driver;
|
||||
static int kgdb_tty_line;
|
||||
|
||||
#ifdef CONFIG_KDB_KEYBOARD
|
||||
static int kgdboc_register_kbd(char **cptr)
|
||||
{
|
||||
if (strncmp(*cptr, "kbd", 3) == 0) {
|
||||
if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
|
||||
kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
|
||||
kdb_poll_idx++;
|
||||
if (cptr[0][3] == ',')
|
||||
*cptr += 4;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kgdboc_unregister_kbd(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kdb_poll_idx; i++) {
|
||||
if (kdb_poll_funcs[i] == kdb_get_kbd_char) {
|
||||
kdb_poll_idx--;
|
||||
kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx];
|
||||
kdb_poll_funcs[kdb_poll_idx] = NULL;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else /* ! CONFIG_KDB_KEYBOARD */
|
||||
#define kgdboc_register_kbd(x) 0
|
||||
#define kgdboc_unregister_kbd()
|
||||
#endif /* ! CONFIG_KDB_KEYBOARD */
|
||||
|
||||
static int kgdboc_option_setup(char *opt)
|
||||
{
|
||||
if (strlen(opt) > MAX_CONFIG_LEN) {
|
||||
|
|
@ -45,25 +81,51 @@ static int kgdboc_option_setup(char *opt)
|
|||
|
||||
__setup("kgdboc=", kgdboc_option_setup);
|
||||
|
||||
static void cleanup_kgdboc(void)
|
||||
{
|
||||
kgdboc_unregister_kbd();
|
||||
if (configured == 1)
|
||||
kgdb_unregister_io_module(&kgdboc_io_ops);
|
||||
}
|
||||
|
||||
static int configure_kgdboc(void)
|
||||
{
|
||||
struct tty_driver *p;
|
||||
int tty_line = 0;
|
||||
int err;
|
||||
char *cptr = config;
|
||||
struct console *cons;
|
||||
|
||||
err = kgdboc_option_setup(config);
|
||||
if (err || !strlen(config) || isspace(config[0]))
|
||||
goto noconfig;
|
||||
|
||||
err = -ENODEV;
|
||||
kgdboc_io_ops.is_console = 0;
|
||||
kgdb_tty_driver = NULL;
|
||||
|
||||
p = tty_find_polling_driver(config, &tty_line);
|
||||
if (kgdboc_register_kbd(&cptr))
|
||||
goto do_register;
|
||||
|
||||
p = tty_find_polling_driver(cptr, &tty_line);
|
||||
if (!p)
|
||||
goto noconfig;
|
||||
|
||||
cons = console_drivers;
|
||||
while (cons) {
|
||||
int idx;
|
||||
if (cons->device && cons->device(cons, &idx) == p &&
|
||||
idx == tty_line) {
|
||||
kgdboc_io_ops.is_console = 1;
|
||||
break;
|
||||
}
|
||||
cons = cons->next;
|
||||
}
|
||||
|
||||
kgdb_tty_driver = p;
|
||||
kgdb_tty_line = tty_line;
|
||||
|
||||
do_register:
|
||||
err = kgdb_register_io_module(&kgdboc_io_ops);
|
||||
if (err)
|
||||
goto noconfig;
|
||||
|
|
@ -75,6 +137,7 @@ static int configure_kgdboc(void)
|
|||
noconfig:
|
||||
config[0] = 0;
|
||||
configured = 0;
|
||||
cleanup_kgdboc();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -88,20 +151,18 @@ static int __init init_kgdboc(void)
|
|||
return configure_kgdboc();
|
||||
}
|
||||
|
||||
static void cleanup_kgdboc(void)
|
||||
{
|
||||
if (configured == 1)
|
||||
kgdb_unregister_io_module(&kgdboc_io_ops);
|
||||
}
|
||||
|
||||
static int kgdboc_get_char(void)
|
||||
{
|
||||
if (!kgdb_tty_driver)
|
||||
return -1;
|
||||
return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
|
||||
kgdb_tty_line);
|
||||
}
|
||||
|
||||
static void kgdboc_put_char(u8 chr)
|
||||
{
|
||||
if (!kgdb_tty_driver)
|
||||
return;
|
||||
kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
|
||||
kgdb_tty_line, chr);
|
||||
}
|
||||
|
|
@ -162,6 +223,25 @@ static struct kgdb_io kgdboc_io_ops = {
|
|||
.post_exception = kgdboc_post_exp_handler,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KGDB_SERIAL_CONSOLE
|
||||
/* This is only available if kgdboc is a built in for early debugging */
|
||||
int __init kgdboc_early_init(char *opt)
|
||||
{
|
||||
/* save the first character of the config string because the
|
||||
* init routine can destroy it.
|
||||
*/
|
||||
char save_ch;
|
||||
|
||||
kgdboc_option_setup(opt);
|
||||
save_ch = config[0];
|
||||
init_kgdboc();
|
||||
config[0] = save_ch;
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("ekgdboc", kgdboc_early_init);
|
||||
#endif /* CONFIG_KGDB_SERIAL_CONSOLE */
|
||||
|
||||
module_init(init_kgdboc);
|
||||
module_exit(cleanup_kgdboc);
|
||||
module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
|
||||
|
|
|
|||
|
|
@ -1226,14 +1226,14 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
|||
|
||||
/* Check validity & presence */
|
||||
for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
|
||||
if (mpc52xx_uart_nodes[idx] == op->node)
|
||||
if (mpc52xx_uart_nodes[idx] == op->dev.of_node)
|
||||
break;
|
||||
if (idx >= MPC52xx_PSC_MAXNUM)
|
||||
return -EINVAL;
|
||||
pr_debug("Found %s assigned to ttyPSC%x\n",
|
||||
mpc52xx_uart_nodes[idx]->full_name, idx);
|
||||
|
||||
uartclk = psc_ops->getuartclk(op->node);
|
||||
uartclk = psc_ops->getuartclk(op->dev.of_node);
|
||||
if (uartclk == 0) {
|
||||
dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -1253,7 +1253,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
|||
port->dev = &op->dev;
|
||||
|
||||
/* Search for IRQ and mapbase */
|
||||
ret = of_address_to_resource(op->node, 0, &res);
|
||||
ret = of_address_to_resource(op->dev.of_node, 0, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1263,7 +1263,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
psc_ops->get_irq(port, op->node);
|
||||
psc_ops->get_irq(port, op->dev.of_node);
|
||||
if (port->irq == NO_IRQ) {
|
||||
dev_dbg(&op->dev, "Could not get irq\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -1362,15 +1362,16 @@ mpc52xx_uart_of_enumerate(void)
|
|||
MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
|
||||
|
||||
static struct of_platform_driver mpc52xx_uart_of_driver = {
|
||||
.match_table = mpc52xx_uart_of_match,
|
||||
.probe = mpc52xx_uart_of_probe,
|
||||
.remove = mpc52xx_uart_of_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = mpc52xx_uart_of_suspend,
|
||||
.resume = mpc52xx_uart_of_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = "mpc52xx-psc-uart",
|
||||
.driver = {
|
||||
.name = "mpc52xx-psc-uart",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = mpc52xx_uart_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2071,6 +2071,7 @@ static int mpsc_drv_probe(struct platform_device *dev)
|
|||
|
||||
if (!(rc = mpsc_drv_map_regs(pi, dev))) {
|
||||
mpsc_drv_get_platform_data(pi, dev, dev->id);
|
||||
pi->port.dev = &dev->dev;
|
||||
|
||||
if (!(rc = mpsc_make_ready(pi))) {
|
||||
spin_lock_init(&pi->tx_lock);
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ int nwpserial_register_port(struct uart_port *port)
|
|||
|
||||
mutex_lock(&nwpserial_mutex);
|
||||
|
||||
dn = to_of_device(port->dev)->node;
|
||||
dn = to_of_device(port->dev)->dev.of_node;
|
||||
if (dn == NULL)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
|
|||
int type, struct uart_port *port)
|
||||
{
|
||||
struct resource resource;
|
||||
struct device_node *np = ofdev->node;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
const unsigned int *clk, *spd;
|
||||
const u32 *prop;
|
||||
int ret, prop_size;
|
||||
|
|
@ -88,7 +88,7 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev,
|
|||
int port_type;
|
||||
int ret;
|
||||
|
||||
if (of_find_property(ofdev->node, "used-by-rtas", NULL))
|
||||
if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
|
||||
return -EBUSY;
|
||||
|
||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||
|
|
@ -175,11 +175,13 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
|
|||
};
|
||||
|
||||
static struct of_platform_driver of_platform_serial_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "of_serial",
|
||||
.driver = {
|
||||
.name = "of_serial",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_platform_serial_table,
|
||||
},
|
||||
.probe = of_platform_serial_probe,
|
||||
.remove = of_platform_serial_remove,
|
||||
.match_table = of_platform_serial_table,
|
||||
};
|
||||
|
||||
static int __init of_platform_serial_init(void)
|
||||
|
|
|
|||
|
|
@ -1611,7 +1611,7 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
|
|||
/* Iterate the pmz_ports array to find a matching entry
|
||||
*/
|
||||
for (i = 0; i < MAX_ZS_PORTS; i++)
|
||||
if (pmz_ports[i].node == mdev->ofdev.node) {
|
||||
if (pmz_ports[i].node == mdev->ofdev.dev.of_node) {
|
||||
struct uart_pmac_port *uap = &pmz_ports[i];
|
||||
|
||||
uap->dev = mdev;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,6 @@ struct serial_info {
|
|||
int manfid;
|
||||
int prodid;
|
||||
int c950ctrl;
|
||||
dev_node_t node[4];
|
||||
int line[4];
|
||||
const struct serial_quirk *quirk;
|
||||
};
|
||||
|
|
@ -289,8 +288,6 @@ static void serial_remove(struct pcmcia_device *link)
|
|||
for (i = 0; i < info->ndev; i++)
|
||||
serial8250_unregister_port(info->line[i]);
|
||||
|
||||
info->p_dev->dev_node = NULL;
|
||||
|
||||
if (!info->slave)
|
||||
pcmcia_disable_device(link);
|
||||
}
|
||||
|
|
@ -343,7 +340,6 @@ static int serial_probe(struct pcmcia_device *link)
|
|||
|
||||
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
|
||||
link->io.NumPorts1 = 8;
|
||||
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
|
||||
link->conf.Attributes = CONF_ENABLE_IRQ;
|
||||
if (do_sound) {
|
||||
link->conf.Attributes |= CONF_ENABLE_SPKR;
|
||||
|
|
@ -411,11 +407,6 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
|
|||
}
|
||||
|
||||
info->line[info->ndev] = line;
|
||||
sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
|
||||
info->node[info->ndev].major = TTY_MAJOR;
|
||||
info->node[info->ndev].minor = 0x40 + line;
|
||||
if (info->ndev > 0)
|
||||
info->node[info->ndev - 1].next = &info->node[info->ndev];
|
||||
info->ndev++;
|
||||
|
||||
return 0;
|
||||
|
|
@ -486,7 +477,7 @@ static int simple_config(struct pcmcia_device *link)
|
|||
}
|
||||
if (info->slave) {
|
||||
return setup_serial(link, info, port,
|
||||
link->irq.AssignedIRQ);
|
||||
link->irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -507,10 +498,6 @@ static int simple_config(struct pcmcia_device *link)
|
|||
return -1;
|
||||
|
||||
found_port:
|
||||
i = pcmcia_request_irq(link, &link->irq);
|
||||
if (i != 0)
|
||||
link->irq.AssignedIRQ = 0;
|
||||
|
||||
if (info->multi && (info->manfid == MANFID_3COM))
|
||||
link->conf.ConfigIndex &= ~(0x08);
|
||||
|
||||
|
|
@ -523,7 +510,7 @@ found_port:
|
|||
i = pcmcia_request_configuration(link, &link->conf);
|
||||
if (i != 0)
|
||||
return -1;
|
||||
return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
|
||||
return setup_serial(link, info, link->io.BasePort1, link->irq);
|
||||
}
|
||||
|
||||
static int multi_config_check(struct pcmcia_device *p_dev,
|
||||
|
|
@ -586,13 +573,9 @@ static int multi_config(struct pcmcia_device *link)
|
|||
}
|
||||
}
|
||||
|
||||
i = pcmcia_request_irq(link, &link->irq);
|
||||
if (i != 0) {
|
||||
/* FIXME: comment does not fit, error handling does not fit */
|
||||
printk(KERN_NOTICE
|
||||
"serial_cs: no usable port range found, giving up\n");
|
||||
link->irq.AssignedIRQ = 0;
|
||||
}
|
||||
if (!link->irq)
|
||||
dev_warn(&link->dev,
|
||||
"serial_cs: no usable IRQ found, continuing...\n");
|
||||
|
||||
/*
|
||||
* Apply any configuration quirks.
|
||||
|
|
@ -615,11 +598,11 @@ static int multi_config(struct pcmcia_device *link)
|
|||
if (link->conf.ConfigIndex == 1 ||
|
||||
link->conf.ConfigIndex == 3) {
|
||||
err = setup_serial(link, info, base2,
|
||||
link->irq.AssignedIRQ);
|
||||
link->irq);
|
||||
base2 = link->io.BasePort1;
|
||||
} else {
|
||||
err = setup_serial(link, info, link->io.BasePort1,
|
||||
link->irq.AssignedIRQ);
|
||||
link->irq);
|
||||
}
|
||||
info->c950ctrl = base2;
|
||||
|
||||
|
|
@ -633,10 +616,10 @@ static int multi_config(struct pcmcia_device *link)
|
|||
return 0;
|
||||
}
|
||||
|
||||
setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
|
||||
setup_serial(link, info, link->io.BasePort1, link->irq);
|
||||
for (i = 0; i < info->multi - 1; i++)
|
||||
setup_serial(link, info, base2 + (8 * i),
|
||||
link->irq.AssignedIRQ);
|
||||
link->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -720,7 +703,6 @@ static int serial_config(struct pcmcia_device * link)
|
|||
if (info->quirk->post(link))
|
||||
goto failed;
|
||||
|
||||
link->dev_node = &info->node[0];
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
|
|
|
|||
|
|
@ -83,16 +83,16 @@ struct sci_port {
|
|||
|
||||
/* Interface clock */
|
||||
struct clk *iclk;
|
||||
/* Data clock */
|
||||
struct clk *dclk;
|
||||
/* Function clock */
|
||||
struct clk *fclk;
|
||||
|
||||
struct list_head node;
|
||||
struct dma_chan *chan_tx;
|
||||
struct dma_chan *chan_rx;
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||
struct device *dma_dev;
|
||||
enum sh_dmae_slave_chan_id slave_tx;
|
||||
enum sh_dmae_slave_chan_id slave_rx;
|
||||
unsigned int slave_tx;
|
||||
unsigned int slave_rx;
|
||||
struct dma_async_tx_descriptor *desc_tx;
|
||||
struct dma_async_tx_descriptor *desc_rx[2];
|
||||
dma_cookie_t cookie_tx;
|
||||
|
|
@ -107,6 +107,7 @@ struct sci_port {
|
|||
struct work_struct work_tx;
|
||||
struct work_struct work_rx;
|
||||
struct timer_list rx_timer;
|
||||
unsigned int rx_timeout;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -150,7 +151,11 @@ static int sci_poll_get_char(struct uart_port *port)
|
|||
handle_error(port);
|
||||
continue;
|
||||
}
|
||||
} while (!(status & SCxSR_RDxF(port)));
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
if (!(status & SCxSR_RDxF(port)))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
c = sci_in(port, SCxRDR);
|
||||
|
||||
|
|
@ -674,22 +679,22 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
|||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
if (s->chan_rx) {
|
||||
unsigned long tout;
|
||||
u16 scr = sci_in(port, SCSCR);
|
||||
u16 ssr = sci_in(port, SCxSR);
|
||||
|
||||
/* Disable future Rx interrupts */
|
||||
sci_out(port, SCSCR, scr & ~SCI_CTRL_FLAGS_RIE);
|
||||
if (port->type == PORT_SCIFA) {
|
||||
disable_irq_nosync(irq);
|
||||
scr |= 0x4000;
|
||||
} else {
|
||||
scr &= ~SCI_CTRL_FLAGS_RIE;
|
||||
}
|
||||
sci_out(port, SCSCR, scr);
|
||||
/* Clear current interrupt */
|
||||
sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
|
||||
/* Calculate delay for 1.5 DMA buffers */
|
||||
tout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
|
||||
port->fifosize / 2;
|
||||
dev_dbg(port->dev, "Rx IRQ: setup timeout in %lu ms\n",
|
||||
tout * 1000 / HZ);
|
||||
if (tout < 2)
|
||||
tout = 2;
|
||||
mod_timer(&s->rx_timer, jiffies + tout);
|
||||
dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
|
||||
jiffies, s->rx_timeout);
|
||||
mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -799,7 +804,7 @@ static int sci_notifier(struct notifier_block *self,
|
|||
(phase == CPUFREQ_RESUMECHANGE)) {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
list_for_each_entry(sci_port, &priv->ports, node)
|
||||
sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
|
||||
sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -810,21 +815,17 @@ static void sci_clk_enable(struct uart_port *port)
|
|||
{
|
||||
struct sci_port *sci_port = to_sci_port(port);
|
||||
|
||||
clk_enable(sci_port->dclk);
|
||||
sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
|
||||
|
||||
if (sci_port->iclk)
|
||||
clk_enable(sci_port->iclk);
|
||||
clk_enable(sci_port->iclk);
|
||||
sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
|
||||
clk_enable(sci_port->fclk);
|
||||
}
|
||||
|
||||
static void sci_clk_disable(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *sci_port = to_sci_port(port);
|
||||
|
||||
if (sci_port->iclk)
|
||||
clk_disable(sci_port->iclk);
|
||||
|
||||
clk_disable(sci_port->dclk);
|
||||
clk_disable(sci_port->fclk);
|
||||
clk_disable(sci_port->iclk);
|
||||
}
|
||||
|
||||
static int sci_request_irq(struct sci_port *port)
|
||||
|
|
@ -913,22 +914,26 @@ static void sci_dma_tx_complete(void *arg)
|
|||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
xmit->tail += s->sg_tx.length;
|
||||
xmit->tail += sg_dma_len(&s->sg_tx);
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
|
||||
port->icount.tx += s->sg_tx.length;
|
||||
port->icount.tx += sg_dma_len(&s->sg_tx);
|
||||
|
||||
async_tx_ack(s->desc_tx);
|
||||
s->cookie_tx = -EINVAL;
|
||||
s->desc_tx = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_chars_pending(xmit))
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
schedule_work(&s->work_tx);
|
||||
} else if (port->type == PORT_SCIFA) {
|
||||
u16 ctrl = sci_in(port, SCSCR);
|
||||
sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
/* Locking: called with port lock held */
|
||||
|
|
@ -972,13 +977,13 @@ static void sci_dma_rx_complete(void *arg)
|
|||
unsigned long flags;
|
||||
int count;
|
||||
|
||||
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
|
||||
dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
count = sci_dma_rx_push(s, tty, s->buf_len_rx);
|
||||
|
||||
mod_timer(&s->rx_timer, jiffies + msecs_to_jiffies(5));
|
||||
mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
|
|
@ -999,8 +1004,9 @@ static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
|
|||
s->chan_rx = NULL;
|
||||
s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
|
||||
dma_release_channel(chan);
|
||||
dma_free_coherent(port->dev, s->buf_len_rx * 2,
|
||||
sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
|
||||
if (sg_dma_address(&s->sg_rx[0]))
|
||||
dma_free_coherent(port->dev, s->buf_len_rx * 2,
|
||||
sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
|
||||
if (enable_pio)
|
||||
sci_start_rx(port);
|
||||
}
|
||||
|
|
@ -1050,6 +1056,8 @@ static void sci_submit_rx(struct sci_port *s)
|
|||
sci_rx_dma_release(s, true);
|
||||
return;
|
||||
}
|
||||
dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
|
||||
s->cookie_rx[i], i);
|
||||
}
|
||||
|
||||
s->active_rx = s->cookie_rx[0];
|
||||
|
|
@ -1084,7 +1092,7 @@ static void work_fn_rx(struct work_struct *work)
|
|||
unsigned long flags;
|
||||
int count;
|
||||
|
||||
chan->device->device_terminate_all(chan);
|
||||
chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
|
||||
dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
|
||||
sh_desc->partial, sh_desc->cookie);
|
||||
|
||||
|
|
@ -1107,10 +1115,10 @@ static void work_fn_rx(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
dev_dbg(port->dev, "%s: cookie %d #%d\n", __func__,
|
||||
s->cookie_rx[new], new);
|
||||
|
||||
s->active_rx = s->cookie_rx[!new];
|
||||
|
||||
dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
|
||||
s->cookie_rx[new], new, s->active_rx);
|
||||
}
|
||||
|
||||
static void work_fn_tx(struct work_struct *work)
|
||||
|
|
@ -1131,14 +1139,13 @@ static void work_fn_tx(struct work_struct *work)
|
|||
*/
|
||||
spin_lock_irq(&port->lock);
|
||||
sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
|
||||
sg->dma_address = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
|
||||
sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
|
||||
sg->offset;
|
||||
sg->length = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
|
||||
sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
|
||||
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
|
||||
sg->dma_length = sg->length;
|
||||
spin_unlock_irq(&port->lock);
|
||||
|
||||
BUG_ON(!sg->length);
|
||||
BUG_ON(!sg_dma_len(sg));
|
||||
|
||||
desc = chan->device->device_prep_slave_sg(chan,
|
||||
sg, s->sg_len_tx, DMA_TO_DEVICE,
|
||||
|
|
@ -1173,23 +1180,28 @@ static void work_fn_tx(struct work_struct *work)
|
|||
|
||||
static void sci_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
unsigned short ctrl;
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
if (s->chan_tx) {
|
||||
if (!uart_circ_empty(&s->port.state->xmit) && s->cookie_tx < 0)
|
||||
schedule_work(&s->work_tx);
|
||||
|
||||
return;
|
||||
if (port->type == PORT_SCIFA) {
|
||||
u16 new, scr = sci_in(port, SCSCR);
|
||||
if (s->chan_tx)
|
||||
new = scr | 0x8000;
|
||||
else
|
||||
new = scr & ~0x8000;
|
||||
if (new != scr)
|
||||
sci_out(port, SCSCR, new);
|
||||
}
|
||||
if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
|
||||
s->cookie_tx < 0)
|
||||
schedule_work(&s->work_tx);
|
||||
#endif
|
||||
|
||||
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
|
||||
ctrl = sci_in(port, SCSCR);
|
||||
ctrl |= SCI_CTRL_FLAGS_TIE;
|
||||
sci_out(port, SCSCR, ctrl);
|
||||
if (!s->chan_tx || port->type == PORT_SCIFA) {
|
||||
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
|
||||
ctrl = sci_in(port, SCSCR);
|
||||
sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
|
||||
}
|
||||
}
|
||||
|
||||
static void sci_stop_tx(struct uart_port *port)
|
||||
|
|
@ -1198,6 +1210,8 @@ static void sci_stop_tx(struct uart_port *port)
|
|||
|
||||
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
|
||||
ctrl = sci_in(port, SCSCR);
|
||||
if (port->type == PORT_SCIFA)
|
||||
ctrl &= ~0x8000;
|
||||
ctrl &= ~SCI_CTRL_FLAGS_TIE;
|
||||
sci_out(port, SCSCR, ctrl);
|
||||
}
|
||||
|
|
@ -1208,6 +1222,8 @@ static void sci_start_rx(struct uart_port *port)
|
|||
|
||||
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
|
||||
ctrl |= sci_in(port, SCSCR);
|
||||
if (port->type == PORT_SCIFA)
|
||||
ctrl &= ~0x4000;
|
||||
sci_out(port, SCSCR, ctrl);
|
||||
}
|
||||
|
||||
|
|
@ -1217,6 +1233,8 @@ static void sci_stop_rx(struct uart_port *port)
|
|||
|
||||
/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
|
||||
ctrl = sci_in(port, SCSCR);
|
||||
if (port->type == PORT_SCIFA)
|
||||
ctrl &= ~0x4000;
|
||||
ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
|
||||
sci_out(port, SCSCR, ctrl);
|
||||
}
|
||||
|
|
@ -1251,8 +1269,12 @@ static void rx_timer_fn(unsigned long arg)
|
|||
{
|
||||
struct sci_port *s = (struct sci_port *)arg;
|
||||
struct uart_port *port = &s->port;
|
||||
|
||||
u16 scr = sci_in(port, SCSCR);
|
||||
|
||||
if (port->type == PORT_SCIFA) {
|
||||
scr &= ~0x4000;
|
||||
enable_irq(s->irqs[1]);
|
||||
}
|
||||
sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
|
||||
dev_dbg(port->dev, "DMA Rx timed out\n");
|
||||
schedule_work(&s->work_rx);
|
||||
|
|
@ -1339,8 +1361,7 @@ static void sci_request_dma(struct uart_port *port)
|
|||
sg_init_table(sg, 1);
|
||||
sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
|
||||
(int)buf[i] & ~PAGE_MASK);
|
||||
sg->dma_address = dma[i];
|
||||
sg->dma_length = sg->length;
|
||||
sg_dma_address(sg) = dma[i];
|
||||
}
|
||||
|
||||
INIT_WORK(&s->work_rx, work_fn_rx);
|
||||
|
|
@ -1403,8 +1424,12 @@ static void sci_shutdown(struct uart_port *port)
|
|||
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
#endif
|
||||
unsigned int status, baud, smr_val, max_baud;
|
||||
int t = -1;
|
||||
u16 scfcr = 0;
|
||||
|
||||
/*
|
||||
* earlyprintk comes here early on with port->uartclk set to zero.
|
||||
|
|
@ -1427,7 +1452,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
|
||||
|
||||
if (port->type != PORT_SCI)
|
||||
sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
|
||||
sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
|
||||
|
||||
smr_val = sci_in(port, SCSMR) & 3;
|
||||
if ((termios->c_cflag & CSIZE) == CS7)
|
||||
|
|
@ -1458,10 +1483,32 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
}
|
||||
|
||||
sci_init_pins(port, termios->c_cflag);
|
||||
sci_out(port, SCFCR, (termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0);
|
||||
sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
|
||||
|
||||
sci_out(port, SCSCR, SCSCR_INIT(port));
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||
/*
|
||||
* Calculate delay for 1.5 DMA buffers: see
|
||||
* drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
|
||||
* (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
|
||||
* calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
|
||||
* Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
|
||||
* sizes), but it has been found out experimentally, that this is not
|
||||
* enough: the driver too often needlessly runs on a DMA timeout. 20ms
|
||||
* as a minimum seem to work perfectly.
|
||||
*/
|
||||
if (s->chan_rx) {
|
||||
s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
|
||||
port->fifosize / 2;
|
||||
dev_dbg(port->dev,
|
||||
"DMA Rx t-out %ums, tty t-out %u jiffies\n",
|
||||
s->rx_timeout * 1000 / HZ, port->timeout);
|
||||
if (s->rx_timeout < msecs_to_jiffies(20))
|
||||
s->rx_timeout = msecs_to_jiffies(20);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((termios->c_cflag & CREAD) != 0)
|
||||
sci_start_rx(port);
|
||||
}
|
||||
|
|
@ -1553,10 +1600,10 @@ static struct uart_ops sci_uart_ops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static void __devinit sci_init_single(struct platform_device *dev,
|
||||
struct sci_port *sci_port,
|
||||
unsigned int index,
|
||||
struct plat_sci_port *p)
|
||||
static int __devinit sci_init_single(struct platform_device *dev,
|
||||
struct sci_port *sci_port,
|
||||
unsigned int index,
|
||||
struct plat_sci_port *p)
|
||||
{
|
||||
struct uart_port *port = &sci_port->port;
|
||||
|
||||
|
|
@ -1577,8 +1624,23 @@ static void __devinit sci_init_single(struct platform_device *dev,
|
|||
}
|
||||
|
||||
if (dev) {
|
||||
sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
|
||||
sci_port->dclk = clk_get(&dev->dev, "peripheral_clk");
|
||||
sci_port->iclk = clk_get(&dev->dev, "sci_ick");
|
||||
if (IS_ERR(sci_port->iclk)) {
|
||||
sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
|
||||
if (IS_ERR(sci_port->iclk)) {
|
||||
dev_err(&dev->dev, "can't get iclk\n");
|
||||
return PTR_ERR(sci_port->iclk);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The function clock is optional, ignore it if we can't
|
||||
* find it.
|
||||
*/
|
||||
sci_port->fclk = clk_get(&dev->dev, "sci_fck");
|
||||
if (IS_ERR(sci_port->fclk))
|
||||
sci_port->fclk = NULL;
|
||||
|
||||
sci_port->enable = sci_clk_enable;
|
||||
sci_port->disable = sci_clk_disable;
|
||||
port->dev = &dev->dev;
|
||||
|
|
@ -1605,6 +1667,7 @@ static void __devinit sci_init_single(struct platform_device *dev,
|
|||
#endif
|
||||
|
||||
memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
|
||||
|
|
@ -1754,8 +1817,11 @@ static int sci_remove(struct platform_device *dev)
|
|||
cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
list_for_each_entry(p, &priv->ports, node)
|
||||
list_for_each_entry(p, &priv->ports, node) {
|
||||
uart_remove_one_port(&sci_uart_driver, &p->port);
|
||||
clk_put(p->iclk);
|
||||
clk_put(p->fclk);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
kfree(priv);
|
||||
|
|
@ -1781,7 +1847,9 @@ static int __devinit sci_probe_single(struct platform_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
sci_init_single(dev, sciport, index, p);
|
||||
ret = sci_init_single(dev, sciport, index, p);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
|
|||
if (err)
|
||||
goto out_free_con_read_page;
|
||||
|
||||
sunserial_console_match(&sunhv_console, op->node,
|
||||
sunserial_console_match(&sunhv_console, op->dev.of_node,
|
||||
&sunhv_reg, port->line, false);
|
||||
|
||||
err = uart_add_one_port(&sunhv_reg, port);
|
||||
|
|
@ -630,8 +630,11 @@ static const struct of_device_id hv_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, hv_match);
|
||||
|
||||
static struct of_platform_driver hv_driver = {
|
||||
.name = "hv",
|
||||
.match_table = hv_match,
|
||||
.driver = {
|
||||
.name = "hv",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = hv_match,
|
||||
},
|
||||
.probe = hv_probe,
|
||||
.remove = __devexit_p(hv_remove),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -883,7 +883,7 @@ static int sunsab_console_setup(struct console *con, char *options)
|
|||
printk("Console: ttyS%d (SAB82532)\n",
|
||||
(sunsab_reg.minor - 64) + con->index);
|
||||
|
||||
sunserial_console_termios(con, to_of_device(up->port.dev)->node);
|
||||
sunserial_console_termios(con, to_of_device(up->port.dev)->dev.of_node);
|
||||
|
||||
switch (con->cflag & CBAUD) {
|
||||
case B150: baud = 150; break;
|
||||
|
|
@ -1026,11 +1026,11 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
|
|||
if (err)
|
||||
goto out1;
|
||||
|
||||
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
|
||||
sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
|
||||
&sunsab_reg, up[0].port.line,
|
||||
false);
|
||||
|
||||
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
|
||||
sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node,
|
||||
&sunsab_reg, up[1].port.line,
|
||||
false);
|
||||
|
||||
|
|
@ -1093,8 +1093,11 @@ static const struct of_device_id sab_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, sab_match);
|
||||
|
||||
static struct of_platform_driver sab_driver = {
|
||||
.name = "sab",
|
||||
.match_table = sab_match,
|
||||
.driver = {
|
||||
.name = "sab",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = sab_match,
|
||||
},
|
||||
.probe = sab_probe,
|
||||
.remove = __devexit_p(sab_remove),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1200,7 +1200,7 @@ static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
|
|||
return -ENODEV;
|
||||
|
||||
printk("%s: %s port at %llx, irq %u\n",
|
||||
to_of_device(up->port.dev)->node->full_name,
|
||||
to_of_device(up->port.dev)->dev.of_node->full_name,
|
||||
(up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
|
||||
(unsigned long long) up->port.mapbase,
|
||||
up->port.irq);
|
||||
|
|
@ -1352,7 +1352,7 @@ static int __init sunsu_console_setup(struct console *co, char *options)
|
|||
spin_lock_init(&port->lock);
|
||||
|
||||
/* Get firmware console settings. */
|
||||
sunserial_console_termios(co, to_of_device(port->dev)->node);
|
||||
sunserial_console_termios(co, to_of_device(port->dev)->dev.of_node);
|
||||
|
||||
memset(&termios, 0, sizeof(struct ktermios));
|
||||
termios.c_cflag = co->cflag;
|
||||
|
|
@ -1409,7 +1409,7 @@ static enum su_type __devinit su_get_type(struct device_node *dp)
|
|||
static int __devinit su_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
static int inst;
|
||||
struct device_node *dp = op->node;
|
||||
struct device_node *dp = op->dev.of_node;
|
||||
struct uart_sunsu_port *up;
|
||||
struct resource *rp;
|
||||
enum su_type type;
|
||||
|
|
@ -1539,8 +1539,11 @@ static const struct of_device_id su_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, su_match);
|
||||
|
||||
static struct of_platform_driver su_driver = {
|
||||
.name = "su",
|
||||
.match_table = su_match,
|
||||
.driver = {
|
||||
.name = "su",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = su_match,
|
||||
},
|
||||
.probe = su_probe,
|
||||
.remove = __devexit_p(su_remove),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ struct uart_sunzilog_port {
|
|||
#endif
|
||||
};
|
||||
|
||||
static void sunzilog_putchar(struct uart_port *port, int ch);
|
||||
|
||||
#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase))
|
||||
#define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT))
|
||||
|
||||
|
|
@ -996,6 +998,50 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int sunzilog_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
unsigned char ch, r1;
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct zilog_channel __iomem *channel
|
||||
= ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
|
||||
|
||||
r1 = read_zsreg(channel, R1);
|
||||
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
|
||||
writeb(ERR_RES, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
}
|
||||
|
||||
ch = readb(&channel->control);
|
||||
ZSDELAY();
|
||||
|
||||
/* This funny hack depends upon BRK_ABRT not interfering
|
||||
* with the other bits we care about in R1.
|
||||
*/
|
||||
if (ch & BRK_ABRT)
|
||||
r1 |= BRK_ABRT;
|
||||
|
||||
if (!(ch & Rx_CH_AV))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
ch = readb(&channel->data);
|
||||
ZSDELAY();
|
||||
|
||||
ch &= up->parity_mask;
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void sunzilog_put_poll_char(struct uart_port *port,
|
||||
unsigned char ch)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port;
|
||||
|
||||
sunzilog_putchar(&up->port, ch);
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static struct uart_ops sunzilog_pops = {
|
||||
.tx_empty = sunzilog_tx_empty,
|
||||
.set_mctrl = sunzilog_set_mctrl,
|
||||
|
|
@ -1013,6 +1059,10 @@ static struct uart_ops sunzilog_pops = {
|
|||
.request_port = sunzilog_request_port,
|
||||
.config_port = sunzilog_config_port,
|
||||
.verify_port = sunzilog_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = sunzilog_get_poll_char,
|
||||
.poll_put_char = sunzilog_put_poll_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int uart_chip_count;
|
||||
|
|
@ -1180,7 +1230,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
|
|||
(sunzilog_reg.minor - 64) + con->index, con->index);
|
||||
|
||||
/* Get firmware console settings. */
|
||||
sunserial_console_termios(con, to_of_device(up->port.dev)->node);
|
||||
sunserial_console_termios(con, to_of_device(up->port.dev)->dev.of_node);
|
||||
|
||||
/* Firmware console speed is limited to 150-->38400 baud so
|
||||
* this hackish cflag thing is OK.
|
||||
|
|
@ -1358,7 +1408,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
|
|||
int keyboard_mouse = 0;
|
||||
int err;
|
||||
|
||||
if (of_find_property(op->node, "keyboard", NULL))
|
||||
if (of_find_property(op->dev.of_node, "keyboard", NULL))
|
||||
keyboard_mouse = 1;
|
||||
|
||||
/* uarts must come before keyboards/mice */
|
||||
|
|
@ -1415,7 +1465,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
|
|||
sunzilog_init_hw(&up[1]);
|
||||
|
||||
if (!keyboard_mouse) {
|
||||
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
|
||||
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
|
||||
&sunzilog_reg, up[0].port.line,
|
||||
false))
|
||||
up->flags |= SUNZILOG_FLAG_IS_CONS;
|
||||
|
|
@ -1425,7 +1475,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
|
|||
rp, sizeof(struct zilog_layout));
|
||||
return err;
|
||||
}
|
||||
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
|
||||
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node,
|
||||
&sunzilog_reg, up[1].port.line,
|
||||
false))
|
||||
up->flags |= SUNZILOG_FLAG_IS_CONS;
|
||||
|
|
@ -1491,8 +1541,11 @@ static const struct of_device_id zs_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, zs_match);
|
||||
|
||||
static struct of_platform_driver zs_driver = {
|
||||
.name = "zs",
|
||||
.match_table = zs_match,
|
||||
.driver = {
|
||||
.name = "zs",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = zs_match,
|
||||
},
|
||||
.probe = zs_probe,
|
||||
.remove = __devexit_p(zs_remove),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -68,12 +68,22 @@ static void timbuart_start_tx(struct uart_port *port)
|
|||
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)
|
||||
{
|
||||
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);
|
||||
iowrite32(TXBF, port->membase + TIMBUART_ISR);
|
||||
iowrite8(ctl, port->membase + TIMBUART_CTRL);
|
||||
iowrite32(TXBF, port->membase + TIMBUART_ISR);
|
||||
}
|
||||
}
|
||||
|
||||
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__);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ static int ulite_receive(struct uart_port *port, int stat)
|
|||
/* stats */
|
||||
if (stat & ULITE_STATUS_RXVALID) {
|
||||
port->icount.rx++;
|
||||
ch = readb(port->membase + ULITE_RX);
|
||||
ch = ioread32be(port->membase + ULITE_RX);
|
||||
|
||||
if (stat & ULITE_STATUS_PARITY)
|
||||
port->icount.parity++;
|
||||
|
|
@ -131,7 +131,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
|
|||
return 0;
|
||||
|
||||
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->icount.tx++;
|
||||
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))
|
||||
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);
|
||||
port->icount.tx++;
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
|
|||
int busy, n = 0;
|
||||
|
||||
do {
|
||||
int stat = readb(port->membase + ULITE_STATUS);
|
||||
int stat = ioread32be(port->membase + ULITE_STATUS);
|
||||
busy = ulite_receive(port, stat);
|
||||
busy |= ulite_transmit(port, stat);
|
||||
n++;
|
||||
|
|
@ -178,7 +178,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port)
|
|||
unsigned int ret;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
ret = readb(port->membase + ULITE_STATUS);
|
||||
ret = ioread32be(port->membase + ULITE_STATUS);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
@ -230,17 +230,17 @@ static int ulite_startup(struct uart_port *port)
|
|||
if (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);
|
||||
writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
||||
iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ulite_shutdown(struct uart_port *port)
|
||||
{
|
||||
writeb(0, port->membase + ULITE_CONTROL);
|
||||
readb(port->membase + ULITE_CONTROL); /* dummy */
|
||||
iowrite32be(0, port->membase + ULITE_CONTROL);
|
||||
ioread32be(port->membase + ULITE_CONTROL); /* dummy */
|
||||
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 */
|
||||
for (i = 0; i < 100000; i++) {
|
||||
val = readb(port->membase + ULITE_STATUS);
|
||||
val = ioread32be(port->membase + ULITE_STATUS);
|
||||
if ((val & ULITE_STATUS_TXFULL) == 0)
|
||||
break;
|
||||
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)
|
||||
{
|
||||
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,
|
||||
|
|
@ -379,8 +379,8 @@ static void ulite_console_write(struct console *co, const char *s,
|
|||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* save and disable interrupt */
|
||||
ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
|
||||
writeb(0, port->membase + ULITE_CONTROL);
|
||||
ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
|
||||
iowrite32be(0, port->membase + ULITE_CONTROL);
|
||||
|
||||
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 */
|
||||
if (ier)
|
||||
writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
||||
iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
|
@ -591,17 +591,17 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match)
|
|||
|
||||
dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
|
||||
|
||||
rc = of_address_to_resource(op->node, 0, &res);
|
||||
rc = of_address_to_resource(op->dev.of_node, 0, &res);
|
||||
if (rc) {
|
||||
dev_err(&op->dev, "invalid address\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(op->node, 0);
|
||||
irq = irq_of_parse_and_map(op->dev.of_node, 0);
|
||||
|
||||
id = of_get_property(op->node, "port-number", NULL);
|
||||
id = of_get_property(op->dev.of_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)
|
||||
|
|
@ -610,13 +610,12 @@ static int __devexit ulite_of_remove(struct of_device *op)
|
|||
}
|
||||
|
||||
static struct of_platform_driver ulite_of_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "uartlite",
|
||||
.match_table = ulite_of_match,
|
||||
.probe = ulite_of_probe,
|
||||
.remove = __devexit_p(ulite_of_remove),
|
||||
.driver = {
|
||||
.name = "uartlite",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ulite_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1197,7 +1197,7 @@ static void uart_firmware_cont(const struct firmware *fw, void *context)
|
|||
static int ucc_uart_probe(struct of_device *ofdev,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct device_node *np = ofdev->node;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
const unsigned int *iprop; /* Integer OF properties */
|
||||
const char *sprop; /* String OF properties */
|
||||
struct uart_qe_port *qe_port = NULL;
|
||||
|
|
@ -1486,9 +1486,11 @@ static struct of_device_id ucc_uart_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, ucc_uart_match);
|
||||
|
||||
static struct of_platform_driver ucc_uart_of_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ucc_uart",
|
||||
.match_table = ucc_uart_match,
|
||||
.driver = {
|
||||
.name = "ucc_uart",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ucc_uart_match,
|
||||
},
|
||||
.probe = ucc_uart_probe,
|
||||
.remove = ucc_uart_remove,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue