Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
03b8cad5
Commit
03b8cad5
authored
Jun 22, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://bk.arm.linux.org.uk/linux-2.6-serial
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
ec2319ca
33e8a4f8
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
813 additions
and
11 deletions
+813
-11
arch/arm/mach-pxa/generic.c
arch/arm/mach-pxa/generic.c
+16
-0
drivers/serial/Kconfig
drivers/serial/Kconfig
+23
-0
drivers/serial/Makefile
drivers/serial/Makefile
+1
-0
drivers/serial/pxa.c
drivers/serial/pxa.c
+62
-11
drivers/serial/serial_lh7a40x.c
drivers/serial/serial_lh7a40x.c
+708
-0
include/linux/serial_core.h
include/linux/serial_core.h
+3
-0
No files found.
arch/arm/mach-pxa/generic.c
View file @
03b8cad5
...
...
@@ -198,10 +198,26 @@ static struct platform_device pxafb_device = {
.
resource
=
pxafb_resources
,
};
static
struct
platform_device
ffuart_device
=
{
.
name
=
"pxa2xx-uart"
,
.
id
=
0
,
};
static
struct
platform_device
btuart_device
=
{
.
name
=
"pxa2xx-uart"
,
.
id
=
1
,
};
static
struct
platform_device
stuart_device
=
{
.
name
=
"pxa2xx-uart"
,
.
id
=
2
,
};
static
struct
platform_device
*
devices
[]
__initdata
=
{
&
pxamci_device
,
&
udc_device
,
&
pxafb_device
,
&
ffuart_device
,
&
btuart_device
,
&
stuart_device
,
};
static
int
__init
pxa_init
(
void
)
...
...
drivers/serial/Kconfig
View file @
03b8cad5
...
...
@@ -603,5 +603,28 @@ config SERIAL_PMACZILOG_CONSOLE
on your PowerMac as the console, you can do so by answering
Y to this option.
config SERIAL_LH7A40X
tristate "Sharp LH7A40X embedded UART support"
depends on ARM && ARCH_LH7A40X
select SERIAL_CORE
help
This enables support for the three on-board UARTs of the
Sharp LH7A40X series CPUs. Choose Y or M.
config SERIAL_LH7A40X_CONSOLE
bool "Support for connsole on Sharp LH7A40X serial port"
depends on SERIAL_LH7A40X=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you wish to use one of the serial ports as the
system console--the system console is the device which
receives all kernel messages and warnings and which allows
logins in single user mode.
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the default system console, but
you can alter that using a kernel command line, for example
"console=ttyAM1".
endmenu
drivers/serial/Makefile
View file @
03b8cad5
...
...
@@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_68360) += 68360serial.o
obj-$(CONFIG_SERIAL_COLDFIRE)
+=
mcfserial.o
obj-$(CONFIG_V850E_UART)
+=
v850e_uart.o
obj-$(CONFIG_SERIAL_PMACZILOG)
+=
pmac_zilog.o
obj-$(CONFIG_SERIAL_LH7A40X)
+=
serial_lh7a40x.o
obj-$(CONFIG_SERIAL_AU1X00)
+=
au1x00_uart.o
obj-$(CONFIG_SERIAL_DZ)
+=
dz.o
obj-$(CONFIG_SERIAL_SH_SCI)
+=
sh-sci.o
...
...
drivers/serial/pxa.c
View file @
03b8cad5
...
...
@@ -35,6 +35,7 @@
#include <linux/circ_buf.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/hardware.h>
...
...
@@ -804,26 +805,76 @@ static struct uart_driver serial_pxa_reg = {
.
cons
=
PXA_CONSOLE
,
};
static
int
__init
serial_pxa_init
(
void
)
static
int
serial_pxa_suspend
(
struct
device
*
_dev
,
u32
state
,
u32
level
)
{
int
i
,
ret
;
struct
uart_pxa_port
*
sport
=
dev_get_drvdata
(
_dev
)
;
ret
=
uart_register_driver
(
&
serial_pxa_reg
);
if
(
ret
)
return
ret
;
if
(
sport
&&
level
==
SUSPEND_DISABLE
)
uart_suspend_port
(
&
serial_pxa_reg
,
&
sport
->
port
);
return
0
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
serial_pxa_ports
);
i
++
)
uart_add_one_port
(
&
serial_pxa_reg
,
&
serial_pxa_ports
[
i
].
port
);
static
int
serial_pxa_resume
(
struct
device
*
_dev
,
u32
level
)
{
struct
uart_pxa_port
*
sport
=
dev_get_drvdata
(
_dev
);
if
(
sport
&&
level
==
RESUME_ENABLE
)
uart_resume_port
(
&
serial_pxa_reg
,
&
sport
->
port
);
return
0
;
}
static
int
serial_pxa_probe
(
struct
device
*
_dev
)
{
struct
platform_device
*
dev
=
to_platform_device
(
_dev
);
serial_pxa_ports
[
dev
->
id
].
port
.
dev
=
_dev
;
uart_add_one_port
(
&
serial_pxa_reg
,
&
serial_pxa_ports
[
dev
->
id
].
port
);
dev_set_drvdata
(
_dev
,
&
serial_pxa_ports
[
dev
->
id
]);
return
0
;
}
static
void
__exit
serial_pxa_exit
(
void
)
static
int
serial_pxa_remove
(
struct
device
*
_dev
)
{
int
i
;
struct
uart_pxa_port
*
sport
=
dev_get_drvdata
(
_dev
);
dev_set_drvdata
(
_dev
,
NULL
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
serial_pxa_ports
);
i
++
)
uart_remove_one_port
(
&
serial_pxa_reg
,
&
serial_pxa_ports
[
i
].
port
);
if
(
sport
)
uart_remove_one_port
(
&
serial_pxa_reg
,
&
sport
->
port
);
return
0
;
}
static
struct
device_driver
serial_pxa_driver
=
{
.
name
=
"pxa2xx-uart"
,
.
bus
=
&
platform_bus_type
,
.
probe
=
serial_pxa_probe
,
.
remove
=
serial_pxa_remove
,
.
suspend
=
serial_pxa_suspend
,
.
resume
=
serial_pxa_resume
,
};
int
__init
serial_pxa_init
(
void
)
{
int
ret
;
ret
=
uart_register_driver
(
&
serial_pxa_reg
);
if
(
ret
!=
0
)
return
ret
;
ret
=
driver_register
(
&
serial_pxa_driver
);
if
(
ret
!=
0
)
uart_unregister_driver
(
&
serial_pxa_reg
);
return
ret
;
}
void
__exit
serial_pxa_exit
(
void
)
{
driver_unregister
(
&
serial_pxa_driver
);
uart_unregister_driver
(
&
serial_pxa_reg
);
}
...
...
drivers/serial/serial_lh7a40x.c
0 → 100644
View file @
03b8cad5
/* drivers/serial/serial_lh7a40x.c
*
* Copyright (C) 2004 Coastal Environmental Systems
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*/
/* Driver for Sharp LH7A40X embedded serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
* Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
*
* ---
*
* This driver supports the embedded UARTs of the Sharp LH7A40X series
* CPUs. While similar to the 16550 and other UART chips, there is
* nothing close to register compatibility. Moreover, some of the
* modem control lines are not available, either in the chip or they
* are lacking in the board-level implementation.
*
* - Use of SIRDIS
* For simplicity, we disable the IR functions of any UART whenever
* we enable it.
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <asm/io.h>
#include <asm/irq.h>
#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#include <asm/arch/serial.h>
#define DEV_MAJOR 204
#define DEV_MINOR 16
#define DEV_NR 3
#define ISR_LOOP_LIMIT 256
#define UR(p,o) _UR ((p)->membase, o)
#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
#define UART_REG_SIZE 32
#define UARTEN (0x01)
/* UART enable */
#define SIRDIS (0x02)
/* Serial IR disable (UART1 only) */
#define RxEmpty (0x10)
#define TxEmpty (0x80)
#define TxFull (0x20)
#define nRxRdy RxEmpty
#define nTxRdy TxFull
#define TxBusy (0x08)
#define RxBreak (0x0800)
#define RxOverrunError (0x0400)
#define RxParityError (0x0200)
#define RxFramingError (0x0100)
#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
#define DCD (0x04)
#define DSR (0x02)
#define CTS (0x01)
#define RxInt (0x01)
#define TxInt (0x02)
#define ModemInt (0x04)
#define RxTimeoutInt (0x08)
#define MSEOI (0x10)
#define WLEN_8 (0x60)
#define WLEN_7 (0x40)
#define WLEN_6 (0x20)
#define WLEN_5 (0x00)
#define WLEN (0x60)
/* Mask for all word-length bits */
#define STP2 (0x08)
#define PEN (0x02)
/* Parity Enable */
#define EPS (0x04)
/* Even Parity Set */
#define FEN (0x10)
/* FIFO Enable */
#define BRK (0x01)
/* Send Break */
struct
uart_port_lh7a40x
{
struct
uart_port
port
;
unsigned
int
statusPrev
;
/* Most recently read modem status */
};
static
void
lh7a40xuart_stop_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_stop
)
{
BIT_CLR
(
port
,
UART_R_INTEN
,
TxInt
);
}
static
void
lh7a40xuart_start_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_start
)
{
BIT_SET
(
port
,
UART_R_INTEN
,
TxInt
);
/* *** FIXME: do I need to check for startup of the
transmitter? The old driver did, but AMBA
doesn't . */
}
static
void
lh7a40xuart_stop_rx
(
struct
uart_port
*
port
)
{
BIT_SET
(
port
,
UART_R_INTEN
,
RxTimeoutInt
|
RxInt
);
}
static
void
lh7a40xuart_enable_ms
(
struct
uart_port
*
port
)
{
BIT_SET
(
port
,
UART_R_INTEN
,
ModemInt
);
}
static
void
#ifdef SUPPORT_SYSRQ
lh7a40xuart_rx_chars
(
struct
uart_port
*
port
,
struct
pt_regs
*
regs
)
#else
lh7a40xuart_rx_chars
(
struct
uart_port
*
port
)
#endif
{
struct
tty_struct
*
tty
=
port
->
info
->
tty
;
int
cbRxMax
=
256
;
/* (Gross) limit on receive */
unsigned
int
data
;
/* Received data and status */
while
(
!
(
UR
(
port
,
UART_R_STATUS
)
&
nRxRdy
)
&&
--
cbRxMax
)
{
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
tty
->
flip
.
work
.
func
((
void
*
)
tty
);
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
printk
(
KERN_WARNING
"TTY_DONT_FLIP set
\n
"
);
return
;
}
}
data
=
UR
(
port
,
UART_R_DATA
);
*
tty
->
flip
.
char_buf_ptr
=
(
unsigned
char
)
data
;
*
tty
->
flip
.
flag_buf_ptr
=
TTY_NORMAL
;
++
port
->
icount
.
rx
;
if
(
data
&
RxError
)
{
/* Quick check, short-circuit */
if
(
data
&
RxBreak
)
{
data
&=
~
(
RxFramingError
|
RxParityError
);
++
port
->
icount
.
brk
;
if
(
uart_handle_break
(
port
))
continue
;
}
else
if
(
data
&
RxParityError
)
++
port
->
icount
.
parity
;
else
if
(
data
&
RxFramingError
)
++
port
->
icount
.
frame
;
if
(
data
&
RxOverrunError
)
++
port
->
icount
.
overrun
;
/* Mask by termios, leave Rx'd byte */
data
&=
port
->
read_status_mask
|
0xff
;
if
(
data
&
RxBreak
)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_BREAK
;
else
if
(
data
&
RxParityError
)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_PARITY
;
else
if
(
data
&
RxFramingError
)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_FRAME
;
}
if
(
uart_handle_sysrq_char
(
port
,
(
unsigned
char
)
data
,
regs
))
continue
;
if
((
data
&
port
->
ignore_status_mask
)
==
0
)
{
++
tty
->
flip
.
flag_buf_ptr
;
++
tty
->
flip
.
char_buf_ptr
;
++
tty
->
flip
.
count
;
}
if
((
data
&
RxOverrunError
)
&&
tty
->
flip
.
count
<
TTY_FLIPBUF_SIZE
)
{
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
*
tty
->
flip
.
char_buf_ptr
++
=
0
;
*
tty
->
flip
.
flag_buf_ptr
++
=
TTY_OVERRUN
;
++
tty
->
flip
.
count
;
}
}
tty_flip_buffer_push
(
tty
);
return
;
}
static
void
lh7a40xuart_tx_chars
(
struct
uart_port
*
port
)
{
struct
circ_buf
*
xmit
=
&
port
->
info
->
xmit
;
int
cbTxMax
=
port
->
fifosize
;
if
(
port
->
x_char
)
{
UR
(
port
,
UART_R_DATA
)
=
port
->
x_char
;
++
port
->
icount
.
tx
;
port
->
x_char
=
0
;
return
;
}
if
(
uart_circ_empty
(
xmit
)
||
uart_tx_stopped
(
port
))
{
lh7a40xuart_stop_tx
(
port
,
0
);
return
;
}
/* Unlike the AMBA UART, the lh7a40x UART does not guarantee
that at least half of the FIFO is empty. Instead, we check
status for every character. Using the AMBA method causes
the transmitter to drop characters. */
do
{
UR
(
port
,
UART_R_DATA
)
=
xmit
->
buf
[
xmit
->
tail
];
xmit
->
tail
=
(
xmit
->
tail
+
1
)
&
(
UART_XMIT_SIZE
-
1
);
++
port
->
icount
.
tx
;
if
(
uart_circ_empty
(
xmit
))
break
;
}
while
(
!
(
UR
(
port
,
UART_R_STATUS
)
&
nTxRdy
)
&&
cbTxMax
--
);
if
(
uart_circ_chars_pending
(
xmit
)
<
WAKEUP_CHARS
)
uart_write_wakeup
(
port
);
if
(
uart_circ_empty
(
xmit
))
lh7a40xuart_stop_tx
(
port
,
0
);
}
static
void
lh7a40xuart_modem_status
(
struct
uart_port
*
port
)
{
unsigned
int
status
=
UR
(
port
,
UART_R_STATUS
);
unsigned
int
delta
=
status
^
((
struct
uart_port_lh7a40x
*
)
port
)
->
statusPrev
;
BIT_SET
(
port
,
UART_R_RAWISR
,
MSEOI
);
/* Clear modem status intr */
if
(
!
delta
)
/* Only happens if we missed 2 transitions */
return
;
((
struct
uart_port_lh7a40x
*
)
port
)
->
statusPrev
=
status
;
if
(
delta
&
DCD
)
uart_handle_dcd_change
(
port
,
status
&
DCD
);
if
(
delta
&
DSR
)
++
port
->
icount
.
dsr
;
if
(
delta
&
CTS
)
uart_handle_cts_change
(
port
,
status
&
CTS
);
wake_up_interruptible
(
&
port
->
info
->
delta_msr_wait
);
}
static
irqreturn_t
lh7a40xuart_int
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
uart_port
*
port
=
dev_id
;
unsigned
int
cLoopLimit
=
ISR_LOOP_LIMIT
;
unsigned
int
isr
=
UR
(
port
,
UART_R_ISR
);
do
{
if
(
isr
&
(
RxInt
|
RxTimeoutInt
))
#ifdef SUPPORT_SYSRQ
lh7a40xuart_rx_chars
(
port
,
regs
);
#else
lh7a40xuart_rx_chars
(
port
);
#endif
if
(
isr
&
ModemInt
)
lh7a40xuart_modem_status
(
port
);
if
(
isr
&
TxInt
)
lh7a40xuart_tx_chars
(
port
);
if
(
--
cLoopLimit
==
0
)
break
;
isr
=
UR
(
port
,
UART_R_ISR
);
}
while
(
isr
&
(
RxInt
|
TxInt
|
RxTimeoutInt
));
return
IRQ_HANDLED
;
}
static
unsigned
int
lh7a40xuart_tx_empty
(
struct
uart_port
*
port
)
{
return
(
UR
(
port
,
UART_R_STATUS
)
&
TxEmpty
)
?
TIOCSER_TEMT
:
0
;
}
static
unsigned
int
lh7a40xuart_get_mctrl
(
struct
uart_port
*
port
)
{
unsigned
int
result
=
0
;
unsigned
int
status
=
UR
(
port
,
UART_R_STATUS
);
if
(
status
&
DCD
)
result
|=
TIOCM_CAR
;
if
(
status
&
DSR
)
result
|=
TIOCM_DSR
;
if
(
status
&
CTS
)
result
|=
TIOCM_CTS
;
return
result
;
}
static
void
lh7a40xuart_set_mctrl
(
struct
uart_port
*
port
,
unsigned
int
mctrl
)
{
/* None of the ports supports DTR. UART1 supports RTS through GPIO. */
/* Note, kernel appears to be setting DTR and RTS on console. */
/* *** FIXME: this deserves more work. There's some work in
tracing all of the IO pins. */
#if 0
if( port->mapbase == UART1_PHYS) {
gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
if (mctrl & TIOCM_RTS)
gpio->pbdr &= ~GPIOB_UART1_RTS;
else
gpio->pbdr |= GPIOB_UART1_RTS;
}
#endif
}
static
void
lh7a40xuart_break_ctl
(
struct
uart_port
*
port
,
int
break_state
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
if
(
break_state
==
-
1
)
BIT_SET
(
port
,
UART_R_FCON
,
BRK
);
/* Assert break */
else
BIT_CLR
(
port
,
UART_R_FCON
,
BRK
);
/* Deassert break */
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
int
lh7a40xuart_startup
(
struct
uart_port
*
port
)
{
int
retval
;
retval
=
request_irq
(
port
->
irq
,
lh7a40xuart_int
,
0
,
"serial_lh7a40x"
,
port
);
if
(
retval
)
return
retval
;
/* Initial modem control-line settings */
((
struct
uart_port_lh7a40x
*
)
port
)
->
statusPrev
=
UR
(
port
,
UART_R_STATUS
);
/* There is presently no configuration option to enable IR.
Thus, we always disable it. */
BIT_SET
(
port
,
UART_R_CON
,
UARTEN
|
SIRDIS
);
BIT_SET
(
port
,
UART_R_INTEN
,
RxTimeoutInt
|
RxInt
);
return
0
;
}
static
void
lh7a40xuart_shutdown
(
struct
uart_port
*
port
)
{
free_irq
(
port
->
irq
,
port
);
BIT_CLR
(
port
,
UART_R_FCON
,
BRK
|
FEN
);
BIT_CLR
(
port
,
UART_R_CON
,
UARTEN
);
}
static
void
lh7a40xuart_set_termios
(
struct
uart_port
*
port
,
struct
termios
*
termios
,
struct
termios
*
old
)
{
unsigned
int
con
;
unsigned
int
inten
;
unsigned
int
fcon
;
unsigned
long
flags
;
unsigned
int
baud
;
unsigned
int
quot
;
baud
=
uart_get_baud_rate
(
port
,
termios
,
old
,
8
,
port
->
uartclk
/
16
);
quot
=
uart_get_divisor
(
port
,
baud
);
/* -1 performed elsewhere */
switch
(
termios
->
c_cflag
&
CSIZE
)
{
case
CS5
:
fcon
=
WLEN_5
;
break
;
case
CS6
:
fcon
=
WLEN_6
;
break
;
case
CS7
:
fcon
=
WLEN_7
;
break
;
case
CS8
:
default:
fcon
=
WLEN_8
;
break
;
}
if
(
termios
->
c_cflag
&
CSTOPB
)
fcon
|=
STP2
;
if
(
termios
->
c_cflag
&
PARENB
)
{
fcon
|=
PEN
;
if
(
!
(
termios
->
c_cflag
&
PARODD
))
fcon
|=
EPS
;
}
if
(
port
->
fifosize
>
1
)
fcon
|=
FEN
;
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
uart_update_timeout
(
port
,
termios
->
c_cflag
,
baud
);
port
->
read_status_mask
=
RxOverrunError
;
if
(
termios
->
c_iflag
&
INPCK
)
port
->
read_status_mask
|=
RxFramingError
|
RxParityError
;
if
(
termios
->
c_iflag
&
(
BRKINT
|
PARMRK
))
port
->
read_status_mask
|=
RxBreak
;
/* Figure mask for status we ignore */
port
->
ignore_status_mask
=
0
;
if
(
termios
->
c_iflag
&
IGNPAR
)
port
->
ignore_status_mask
|=
RxFramingError
|
RxParityError
;
if
(
termios
->
c_iflag
&
IGNBRK
)
{
port
->
ignore_status_mask
|=
RxBreak
;
/* Ignore overrun when ignorning parity */
/* *** FIXME: is this in the right place? */
if
(
termios
->
c_iflag
&
IGNPAR
)
port
->
ignore_status_mask
|=
RxOverrunError
;
}
/* Ignore all receive errors when receive disabled */
if
((
termios
->
c_cflag
&
CREAD
)
==
0
)
port
->
ignore_status_mask
|=
RxError
;
con
=
UR
(
port
,
UART_R_CON
);
inten
=
(
UR
(
port
,
UART_R_INTEN
)
&
~
ModemInt
);
if
(
UART_ENABLE_MS
(
port
,
termios
->
c_cflag
))
inten
|=
ModemInt
;
BIT_CLR
(
port
,
UART_R_CON
,
UARTEN
);
/* Disable UART */
UR
(
port
,
UART_R_INTEN
)
=
0
;
/* Disable interrupts */
UR
(
port
,
UART_R_BRCON
)
=
quot
-
1
;
/* Set baud rate divisor */
UR
(
port
,
UART_R_FCON
)
=
fcon
;
/* Set FIFO and frame ctrl */
UR
(
port
,
UART_R_INTEN
)
=
inten
;
/* Enable interrupts */
UR
(
port
,
UART_R_CON
)
=
con
;
/* Restore UART mode */
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
const
char
*
lh7a40xuart_type
(
struct
uart_port
*
port
)
{
return
port
->
type
==
PORT_LH7A40X
?
"LH7A40X"
:
NULL
;
}
static
void
lh7a40xuart_release_port
(
struct
uart_port
*
port
)
{
release_mem_region
(
port
->
mapbase
,
UART_REG_SIZE
);
}
static
int
lh7a40xuart_request_port
(
struct
uart_port
*
port
)
{
return
request_mem_region
(
port
->
mapbase
,
UART_REG_SIZE
,
"serial_lh7a40x"
)
!=
NULL
?
0
:
-
EBUSY
;
}
static
void
lh7a40xuart_config_port
(
struct
uart_port
*
port
,
int
flags
)
{
if
(
flags
&
UART_CONFIG_TYPE
)
{
port
->
type
=
PORT_LH7A40X
;
lh7a40xuart_request_port
(
port
);
}
}
static
int
lh7a40xuart_verify_port
(
struct
uart_port
*
port
,
struct
serial_struct
*
ser
)
{
int
ret
=
0
;
if
(
ser
->
type
!=
PORT_UNKNOWN
&&
ser
->
type
!=
PORT_LH7A40X
)
ret
=
-
EINVAL
;
if
(
ser
->
irq
<
0
||
ser
->
irq
>=
NR_IRQS
)
ret
=
-
EINVAL
;
if
(
ser
->
baud_base
<
9600
)
/* *** FIXME: is this true? */
ret
=
-
EINVAL
;
return
ret
;
}
static
struct
uart_ops
lh7a40x_uart_ops
=
{
.
tx_empty
=
lh7a40xuart_tx_empty
,
.
set_mctrl
=
lh7a40xuart_set_mctrl
,
.
get_mctrl
=
lh7a40xuart_get_mctrl
,
.
stop_tx
=
lh7a40xuart_stop_tx
,
.
start_tx
=
lh7a40xuart_start_tx
,
.
stop_rx
=
lh7a40xuart_stop_rx
,
.
enable_ms
=
lh7a40xuart_enable_ms
,
.
break_ctl
=
lh7a40xuart_break_ctl
,
.
startup
=
lh7a40xuart_startup
,
.
shutdown
=
lh7a40xuart_shutdown
,
.
set_termios
=
lh7a40xuart_set_termios
,
.
type
=
lh7a40xuart_type
,
.
release_port
=
lh7a40xuart_release_port
,
.
request_port
=
lh7a40xuart_request_port
,
.
config_port
=
lh7a40xuart_config_port
,
.
verify_port
=
lh7a40xuart_verify_port
,
};
static
struct
uart_port_lh7a40x
lh7a40x_ports
[
DEV_NR
]
=
{
{
.
port
=
{
.
membase
=
(
void
*
)
io_p2v
(
UART1_PHYS
),
.
mapbase
=
UART1_PHYS
,
.
iotype
=
SERIAL_IO_MEM
,
.
irq
=
IRQ_UART1INTR
,
.
uartclk
=
14745600
/
2
,
.
fifosize
=
16
,
.
ops
=
&
lh7a40x_uart_ops
,
.
flags
=
ASYNC_BOOT_AUTOCONF
,
.
line
=
0
,
},
},
{
.
port
=
{
.
membase
=
(
void
*
)
io_p2v
(
UART2_PHYS
),
.
mapbase
=
UART2_PHYS
,
.
iotype
=
SERIAL_IO_MEM
,
.
irq
=
IRQ_UART2INTR
,
.
uartclk
=
14745600
/
2
,
.
fifosize
=
16
,
.
ops
=
&
lh7a40x_uart_ops
,
.
flags
=
ASYNC_BOOT_AUTOCONF
,
.
line
=
1
,
},
},
{
.
port
=
{
.
membase
=
(
void
*
)
io_p2v
(
UART3_PHYS
),
.
mapbase
=
UART3_PHYS
,
.
iotype
=
SERIAL_IO_MEM
,
.
irq
=
IRQ_UART3INTR
,
.
uartclk
=
14745600
/
2
,
.
fifosize
=
16
,
.
ops
=
&
lh7a40x_uart_ops
,
.
flags
=
ASYNC_BOOT_AUTOCONF
,
.
line
=
2
,
},
},
};
#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
# define LH7A40X_CONSOLE NULL
#else
# define LH7A40X_CONSOLE &lh7a40x_console
static
void
lh7a40xuart_console_write
(
struct
console
*
co
,
const
char
*
s
,
unsigned
int
count
)
{
struct
uart_port
*
port
=
&
lh7a40x_ports
[
co
->
index
].
port
;
unsigned
int
con
=
UR
(
port
,
UART_R_CON
);
unsigned
int
inten
=
UR
(
port
,
UART_R_INTEN
);
UR
(
port
,
UART_R_INTEN
)
=
0
;
/* Disable all interrupts */
BIT_SET
(
port
,
UART_R_CON
,
UARTEN
|
SIRDIS
);
/* Enable UART */
for
(;
count
--
>
0
;
++
s
)
{
while
(
UR
(
port
,
UART_R_STATUS
)
&
nTxRdy
)
;
UR
(
port
,
UART_R_DATA
)
=
*
s
;
if
(
*
s
==
'\n'
)
{
while
((
UR
(
port
,
UART_R_STATUS
)
&
TxBusy
))
;
UR
(
port
,
UART_R_DATA
)
=
'\r'
;
}
}
/* Wait until all characters are sent */
while
(
UR
(
port
,
UART_R_STATUS
)
&
TxBusy
)
;
/* Restore control and interrupt mask */
UR
(
port
,
UART_R_CON
)
=
con
;
UR
(
port
,
UART_R_INTEN
)
=
inten
;
}
static
void
__init
lh7a40xuart_console_get_options
(
struct
uart_port
*
port
,
int
*
baud
,
int
*
parity
,
int
*
bits
)
{
if
(
UR
(
port
,
UART_R_CON
)
&
UARTEN
)
{
unsigned
int
fcon
=
UR
(
port
,
UART_R_FCON
);
unsigned
int
quot
=
UR
(
port
,
UART_R_BRCON
)
+
1
;
switch
(
fcon
&
(
PEN
|
EPS
))
{
default:
*
parity
=
'n'
;
break
;
case
PEN
:
*
parity
=
'o'
;
break
;
case
PEN
|
EPS
:
*
parity
=
'e'
;
break
;
}
switch
(
fcon
&
WLEN
)
{
default:
case
WLEN_8
:
*
bits
=
8
;
break
;
case
WLEN_7
:
*
bits
=
7
;
break
;
case
WLEN_6
:
*
bits
=
6
;
break
;
case
WLEN_5
:
*
bits
=
5
;
break
;
}
*
baud
=
port
->
uartclk
/
(
16
*
quot
);
}
}
static
int
__init
lh7a40xuart_console_setup
(
struct
console
*
co
,
char
*
options
)
{
struct
uart_port
*
port
;
int
baud
=
38400
;
int
bits
=
8
;
int
parity
=
'n'
;
int
flow
=
'n'
;
if
(
co
->
index
>=
DEV_NR
)
/* Bounds check on device number */
co
->
index
=
0
;
port
=
&
lh7a40x_ports
[
co
->
index
].
port
;
if
(
options
)
uart_parse_options
(
options
,
&
baud
,
&
parity
,
&
bits
,
&
flow
);
else
lh7a40xuart_console_get_options
(
port
,
&
baud
,
&
parity
,
&
bits
);
return
uart_set_options
(
port
,
co
,
baud
,
parity
,
bits
,
flow
);
}
extern
struct
uart_driver
lh7a40x_reg
;
static
struct
console
lh7a40x_console
=
{
.
name
=
"ttyAM"
,
.
write
=
lh7a40xuart_console_write
,
.
device
=
uart_console_device
,
.
setup
=
lh7a40xuart_console_setup
,
.
flags
=
CON_PRINTBUFFER
,
.
index
=
-
1
,
.
data
=
&
lh7a40x_reg
,
};
static
int
__init
lh7a40xuart_console_init
(
void
)
{
register_console
(
&
lh7a40x_console
);
return
0
;
}
console_initcall
(
lh7a40xuart_console_init
);
#endif
static
struct
uart_driver
lh7a40x_reg
=
{
.
owner
=
THIS_MODULE
,
.
driver_name
=
"ttyAM"
,
.
dev_name
=
"ttyAM"
,
.
major
=
DEV_MAJOR
,
.
minor
=
DEV_MINOR
,
.
nr
=
DEV_NR
,
.
cons
=
LH7A40X_CONSOLE
,
};
static
int
__init
lh7a40xuart_init
(
void
)
{
int
ret
;
printk
(
KERN_INFO
"serial: LH7A40X serial driver
\n
"
);
ret
=
uart_register_driver
(
&
lh7a40x_reg
);
if
(
ret
==
0
)
{
int
i
;
for
(
i
=
0
;
i
<
DEV_NR
;
i
++
)
uart_add_one_port
(
&
lh7a40x_reg
,
&
lh7a40x_ports
[
i
].
port
);
}
return
ret
;
}
static
void
__exit
lh7a40xuart_exit
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
DEV_NR
;
i
++
)
uart_remove_one_port
(
&
lh7a40x_reg
,
&
lh7a40x_ports
[
i
].
port
);
uart_unregister_driver
(
&
lh7a40x_reg
);
}
module_init
(
lh7a40xuart_init
);
module_exit
(
lh7a40xuart_exit
);
MODULE_AUTHOR
(
"Marc Singer"
);
MODULE_DESCRIPTION
(
"Sharp LH7A40X serial port driver"
);
MODULE_LICENSE
(
"GPL"
);
include/linux/serial_core.h
View file @
03b8cad5
...
...
@@ -80,6 +80,9 @@
/* SGI IP22 aka Indy / Challenge S / Indigo 2 */
#define PORT_IP22ZILOG 56
/* Sharp LH7a40x -- an ARM9 SoC series */
#define PORT_LH7A40X 57
#ifdef __KERNEL__
#include <linux/config.h>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment