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
nexedi
linux
Commits
70ca2c43
Commit
70ca2c43
authored
Nov 14, 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
f52ef599
3f6a3bd4
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1168 additions
and
351 deletions
+1168
-351
drivers/serial/s3c2410.c
drivers/serial/s3c2410.c
+1106
-323
include/asm-arm/arch-s3c2410/regs-serial.h
include/asm-arm/arch-s3c2410/regs-serial.h
+62
-28
No files found.
drivers/serial/s3c2410.c
View file @
70ca2c43
/*
* linux/drivers/
char
/s3c2410.c
* linux/drivers/
serial
/s3c2410.c
*
* Driver for onboard UARTs on the Samsung S3C24
10
* Driver for onboard UARTs on the Samsung S3C24
XX
*
* Based on drivers/char/serial.c and drivers/char/21285.c
*
...
...
@@ -9,55 +9,152 @@
*
* Changelog:
*
*/
* 22-Jul-2004 BJD Finished off device rewrite
*
* 21-Jul-2004 BJD Thanks to <herbet@13thfloor.at> for pointing out
* problems with baud rate and loss of IR settings. Update
* to add configuration via platform_device structure
*
* 28-Sep-2004 BJD Re-write for the following items
* - S3C2410 and S3C2440 serial support
* - Power Management support
* - Fix console via IrDA devices
* - SysReq (Herbert Ptzl)
* - Break character handling (Herbert Ptzl)
* - spin-lock initialisation (Dimitry Andric)
* - added clock control
* - updated init code to use platform_device info
*/
/* Hote on 2410 error handling
*
* The s3c2410 manual has a love/hate affair with the contents of the
* UERSTAT register in the UART blocks, and keeps marking some of the
* error bits as reserved. Having checked with the s3c2410x01,
* it copes with BREAKs properly, so I am happy to ignore the RESERVED
* feature from the latter versions of the manual.
*
* If it becomes aparrent that latter versions of the 2410 remove these
* bits, then action will have to be taken to differentiate the versions
* and change the policy on BREAK
*
* BJD, 04-Nov-2004
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_S3C2410_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/sysrq.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/hardware/clock.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/mach-types.h>
/* structures */
struct
s3c24xx_uart_info
{
char
*
name
;
unsigned
int
type
;
unsigned
int
fifosize
;
unsigned
long
rx_fifomask
;
unsigned
long
rx_fifoshift
;
unsigned
long
tx_fifomask
;
unsigned
long
tx_fifoshift
;
unsigned
long
tx_fifofull
;
/* clock source control */
int
(
*
get_clksrc
)(
struct
uart_port
*
,
struct
s3c24xx_uart_clksrc
*
clk
);
int
(
*
set_clksrc
)(
struct
uart_port
*
,
struct
s3c24xx_uart_clksrc
*
clk
);
};
struct
s3c24xx_uart_port
{
unsigned
char
rx_claimed
;
unsigned
char
tx_claimed
;
struct
s3c24xx_uart_info
*
info
;
struct
s3c24xx_uart_clksrc
*
clksrc
;
struct
clk
*
clk
;
struct
clk
*
baudclk
;
struct
uart_port
port
;
};
/* configuration defines */
#if 0
#include <asm/debug-ll.h>
#define dbg(x...) llprintk(x)
#if 1
/* send debug to the low-level output routines */
extern void printascii(const char *);
static void
s3c24xx_serial_dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
va_start(va, fmt);
vsprintf(buff, fmt, va);
va_end(va);
printascii(buff);
}
#define dbg(x...) s3c24xx_serial_dbg(x)
#else
#define dbg(x...)
#define dbg(x...)
printk(KERN_DEBUG "s3c24xx: ");
#endif
#else
/* no debug */
#define dbg(x...) do {} while(0)
#endif
/* UART name and device definitions */
#define SERIAL_S3C2410_NAME "ttySAC"
#define SERIAL_S3C2410_MAJOR 204
#define SERIAL_S3C2410_MINOR 64
#define S3C24XX_SERIAL_NAME "ttySAC"
#define S3C24XX_SERIAL_DEVFS "tts/"
#define S3C24XX_SERIAL_MAJOR 204
#define S3C24XX_SERIAL_MINOR 64
/* conversion functions */
#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
/* we can support 3 uarts, but not always use them */
#define NR_PORTS (3)
static
const
char
serial_s3c2410_name
[]
=
"Samsung S3C2410 UART"
;
/* port irq numbers */
#define TX_IRQ(port) ((port)->irq + 1)
#define RX_IRQ(port) ((port)->irq)
#define tx_enabled(port) ((port)->unused[0])
#define rx_enabled(port) ((port)->unused[1])
/* flag to ignore all characters comming in */
#define RXSTAT_DUMMY_READ (0x10000000)
/* access functions */
/* register access controls */
#define portaddr(port, reg) ((
void *)((port)->membase + (reg)
))
#define portaddr(port, reg) ((
port)->membase + (reg
))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
...
...
@@ -68,102 +165,230 @@ static const char serial_s3c2410_name[] = "Samsung S3C2410 UART";
#define wr_regl(port, reg, val) \
do { __raw_writel(val, portaddr(port, reg)); } while(0)
/* macros to change one thing to another */
#define tx_enabled(port) ((port)->unused[0])
#define rx_enabled(port) ((port)->unused[1])
/* flag to ignore all characters comming in */
#define RXSTAT_DUMMY_READ (0x10000000)
static
inline
struct
s3c24xx_uart_port
*
to_ourport
(
struct
uart_port
*
port
)
{
return
container_of
(
port
,
struct
s3c24xx_uart_port
,
port
);
}
/* translate a port to the device name */
static
inline
char
*
s3c24xx_serial_portname
(
struct
uart_port
*
port
)
{
return
to_platform_device
(
port
->
dev
)
->
name
;
}
static
int
s3c24xx_serial_txempty_nofifo
(
struct
uart_port
*
port
)
{
return
(
rd_regl
(
port
,
S3C2410_UTRSTAT
)
&
S3C2410_UTRSTAT_TXE
);
}
static
void
s3c24xx_serial_rx_enable
(
struct
uart_port
*
port
)
{
unsigned
long
flags
;
unsigned
int
ucon
,
ufcon
;
int
count
=
10000
;
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
while
(
--
count
&&
!
s3c24xx_serial_txempty_nofifo
(
port
))
udelay
(
100
);
ufcon
=
rd_regl
(
port
,
S3C2410_UFCON
);
ufcon
|=
S3C2410_UFCON_RESETRX
;
wr_regl
(
port
,
S3C2410_UFCON
,
ufcon
);
ucon
=
rd_regl
(
port
,
S3C2410_UCON
);
ucon
|=
S3C2410_UCON_RXIRQMODE
;
wr_regl
(
port
,
S3C2410_UCON
,
ucon
);
rx_enabled
(
port
)
=
1
;
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
void
s3c24xx_serial_rx_disable
(
struct
uart_port
*
port
)
{
unsigned
long
flags
;
unsigned
int
ucon
;
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
ucon
=
rd_regl
(
port
,
S3C2410_UCON
);
ucon
&=
~
S3C2410_UCON_RXIRQMODE
;
wr_regl
(
port
,
S3C2410_UCON
,
ucon
);
/* code */
rx_enabled
(
port
)
=
0
;
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
void
s
erial_s3c2410
_stop_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_stop
)
s
3c24xx_serial
_stop_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_stop
)
{
if
(
tx_enabled
(
port
))
{
disable_irq
(
TX_IRQ
(
port
));
tx_enabled
(
port
)
=
0
;
if
(
port
->
flags
&
UPF_CONS_FLOW
)
s3c24xx_serial_rx_enable
(
port
);
}
}
static
void
s
erial_s3c2410
_start_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_start
)
s
3c24xx_serial
_start_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_start
)
{
if
(
!
tx_enabled
(
port
))
{
if
(
port
->
flags
&
UPF_CONS_FLOW
)
s3c24xx_serial_rx_disable
(
port
);
enable_irq
(
TX_IRQ
(
port
));
tx_enabled
(
port
)
=
1
;
}
}
static
void
serial_s3c2410_stop_rx
(
struct
uart_port
*
port
)
static
void
s3c24xx_serial_stop_rx
(
struct
uart_port
*
port
)
{
if
(
rx_enabled
(
port
))
{
dbg
(
"s
erial_s3c2410
_stop_rx: port=%p
\n
"
,
port
);
dbg
(
"s
3c24xx_serial
_stop_rx: port=%p
\n
"
,
port
);
disable_irq
(
RX_IRQ
(
port
));
rx_enabled
(
port
)
=
0
;
}
}
static
void
serial_s3c2410_enable_ms
(
struct
uart_port
*
port
)
static
void
s3c24xx_serial_enable_ms
(
struct
uart_port
*
port
)
{
}
static
inline
struct
s3c24xx_uart_info
*
s3c24xx_port_to_info
(
struct
uart_port
*
port
)
{
return
to_ourport
(
port
)
->
info
;
}
static
inline
struct
s3c2410_uartcfg
*
s3c24xx_port_to_cfg
(
struct
uart_port
*
port
)
{
if
(
port
->
dev
==
NULL
)
return
NULL
;
return
(
struct
s3c2410_uartcfg
*
)
port
->
dev
->
platform_data
;
}
static
int
s3c24xx_serial_rx_fifocnt
(
struct
s3c24xx_uart_port
*
ourport
,
unsigned
long
ufstat
)
{
struct
s3c24xx_uart_info
*
info
=
ourport
->
info
;
return
(
ufstat
&
info
->
rx_fifomask
)
>>
info
->
rx_fifoshift
;
}
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
static
irqreturn_t
s
erial_s3c2410
_rx_chars
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
s
3c24xx_serial
_rx_chars
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
uart_port
*
port
=
dev_id
;
struct
s3c24xx_uart_port
*
ourport
=
dev_id
;
struct
uart_port
*
port
=
&
ourport
->
port
;
struct
tty_struct
*
tty
=
port
->
info
->
tty
;
unsigned
int
ufcon
,
ch
,
flag
,
rxs
,
uf
stat
;
int
max_count
=
256
;
unsigned
int
ufcon
,
ch
,
flag
,
ufstat
,
uer
stat
;
int
max_count
=
64
;
while
(
max_count
--
>
0
)
{
ufcon
=
rd_regl
(
port
,
S3C2410_UFCON
);
ufstat
=
rd_regl
(
port
,
S3C2410_UFSTAT
);
if
(
S3C2410_UFCON_RXC
(
ufstat
)
==
0
)
if
(
s3c24xx_serial_rx_fifocnt
(
ourport
,
ufstat
)
==
0
)
break
;
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
if
(
tty
->
low_latency
)
tty_flip_buffer_push
(
tty
);
/*
* If this failed then we will throw away the
* bytes but must do so to clear interrupts
*/
}
uerstat
=
rd_regl
(
port
,
S3C2410_UERSTAT
);
ch
=
rd_regb
(
port
,
S3C2410_URXH
);
if
(
port
->
flags
&
UPF_CONS_FLOW
)
{
int
txe
=
s3c24xx_serial_txempty_nofifo
(
port
);
if
(
rx_enabled
(
port
))
{
if
(
!
txe
)
{
rx_enabled
(
port
)
=
0
;
continue
;
}
}
else
{
if
(
txe
)
{
ufcon
|=
S3C2410_UFCON_RESETRX
;
wr_regl
(
port
,
S3C2410_UFCON
,
ufcon
);
rx_enabled
(
port
)
=
1
;
goto
out
;
}
continue
;
}
}
/* insert the character into the buffer */
flag
=
TTY_NORMAL
;
port
->
icount
.
rx
++
;
rxs
=
rd_regb
(
port
,
S3C2410_UERSTAT
)
|
RXSTAT_DUMMY_READ
;
if
(
uerstat
&
S3C2410_UERSTAT_ANY
)
{
dbg
(
"rxerr: port ch=0x%02x, rxs=0x%08x
\n
"
,
ch
,
uerstat
);
if
(
rxs
&
S3C2410_UERSTAT_ANY
)
{
if
(
rxs
&
S3C2410_UERSTAT_FRAME
)
/* check for break */
if
(
uerstat
&
S3C2410_UERSTAT_BREAK
)
{
dbg
(
"break!
\n
"
);
port
->
icount
.
brk
++
;
if
(
uart_handle_break
(
port
))
goto
ignore_char
;
}
if
(
uerstat
&
S3C2410_UERSTAT_FRAME
)
port
->
icount
.
frame
++
;
if
(
rxs
&
S3C2410_UERSTAT_OVERRUN
)
if
(
uerstat
&
S3C2410_UERSTAT_OVERRUN
)
port
->
icount
.
overrun
++
;
rxs
&=
port
->
read_status_mask
;
uerstat
&=
port
->
read_status_mask
;
if
(
rxs
&
S3C2410_UERSTAT_PARITY
)
if
(
uerstat
&
S3C2410_UERSTAT_BREAK
)
flag
=
TTY_BREAK
;
else
if
(
uerstat
&
S3C2410_UERSTAT_PARITY
)
flag
=
TTY_PARITY
;
else
if
(
rxs
&
(
S3C2410_UERSTAT_FRAME
|
S3C2410_UERSTAT_OVERRUN
))
else
if
(
uerstat
&
(
S3C2410_UERSTAT_FRAME
|
S3C2410_UERSTAT_OVERRUN
))
flag
=
TTY_FRAME
;
}
if
((
rxs
&
port
->
ignore_status_mask
)
==
0
)
{
if
(
uart_handle_sysrq_char
(
port
,
ch
,
regs
))
goto
ignore_char
;
if
((
uerstat
&
port
->
ignore_status_mask
)
==
0
)
{
tty_insert_flip_char
(
tty
,
ch
,
flag
);
}
if
((
rxs
&
S3C2410_UERSTAT_OVERRUN
)
&&
if
((
uerstat
&
S3C2410_UERSTAT_OVERRUN
)
&&
tty
->
flip
.
count
<
TTY_FLIPBUF_SIZE
)
{
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char
(
tty
,
0
,
TTY_OVERRUN
);
}
ignore_char:
continue
;
}
tty_flip_buffer_push
(
tty
);
...
...
@@ -171,10 +396,10 @@ serial_s3c2410_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
return
IRQ_HANDLED
;
}
static
irqreturn_t
serial_s3c2410_tx_chars
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
static
irqreturn_t
s3c24xx_serial_tx_chars
(
int
irq
,
void
*
id
,
struct
pt_regs
*
regs
)
{
struct
uart_port
*
port
=
(
struct
uart_port
*
)
dev_id
;
struct
s3c24xx_uart_port
*
ourport
=
id
;
struct
uart_port
*
port
=
&
ourport
->
port
;
struct
circ_buf
*
xmit
=
&
port
->
info
->
xmit
;
int
count
=
256
;
...
...
@@ -190,14 +415,14 @@ serial_s3c2410_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
*/
if
(
uart_circ_empty
(
xmit
)
||
uart_tx_stopped
(
port
))
{
s
erial_s3c2410
_stop_tx
(
port
,
0
);
s
3c24xx_serial
_stop_tx
(
port
,
0
);
goto
out
;
}
/* try and drain the buffer... */
while
(
!
uart_circ_empty
(
xmit
)
&&
count
--
>
0
)
{
if
(
rd_regl
(
port
,
S3C2410_UFSTAT
)
&
S3C2410_UFSTAT_TXFULL
)
if
(
rd_regl
(
port
,
S3C2410_UFSTAT
)
&
ourport
->
info
->
tx_fifofull
)
break
;
wr_regb
(
port
,
S3C2410_UTXH
,
xmit
->
buf
[
xmit
->
tail
]);
...
...
@@ -209,22 +434,31 @@ serial_s3c2410_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
uart_write_wakeup
(
port
);
if
(
uart_circ_empty
(
xmit
))
s
erial_s3c2410
_stop_tx
(
port
,
0
);
s
3c24xx_serial
_stop_tx
(
port
,
0
);
out:
return
IRQ_HANDLED
;
}
static
unsigned
int
serial_s3c2410_tx_empty
(
struct
uart_port
*
port
)
static
unsigned
int
s3c24xx_serial_tx_empty
(
struct
uart_port
*
port
)
{
unsigned
int
ufcon
=
rd_regl
(
port
,
S3C2410_UFCON
);
return
(
S3C2410_UFCON_TXC
(
ufcon
)
!=
0
)
?
0
:
TIOCSER_TEMT
;
struct
s3c24xx_uart_info
*
info
=
s3c24xx_port_to_info
(
port
);
unsigned
long
ufstat
=
rd_regl
(
port
,
S3C2410_UFSTAT
);
unsigned
long
ufcon
=
rd_regl
(
port
,
S3C2410_UFCON
);
if
(
ufcon
&
S3C2410_UFCON_FIFOMODE
)
{
if
((
ufstat
&
info
->
tx_fifomask
)
!=
0
||
(
ufstat
&
info
->
tx_fifofull
))
return
0
;
return
1
;
}
return
s3c24xx_serial_txempty_nofifo
(
port
);
}
/* no modem control lines */
static
unsigned
int
serial_s3c2410_get_mctrl
(
struct
uart_port
*
port
)
static
unsigned
int
s3c24xx_serial_get_mctrl
(
struct
uart_port
*
port
)
{
unsigned
int
umstat
=
rd_regb
(
port
,
S3C2410_UMSTAT
);
...
...
@@ -234,13 +468,12 @@ serial_s3c2410_get_mctrl(struct uart_port *port)
return
TIOCM_CAR
|
TIOCM_DSR
;
}
static
void
serial_s3c2410_set_mctrl
(
struct
uart_port
*
port
,
unsigned
int
mctrl
)
static
void
s3c24xx_serial_set_mctrl
(
struct
uart_port
*
port
,
unsigned
int
mctrl
)
{
/* todo - possibly remove AFC and do manual CTS */
}
static
void
s
erial_s3c2410
_break_ctl
(
struct
uart_port
*
port
,
int
break_state
)
static
void
s
3c24xx_serial
_break_ctl
(
struct
uart_port
*
port
,
int
break_state
)
{
unsigned
long
flags
;
unsigned
int
ucon
;
...
...
@@ -259,46 +492,250 @@ static void serial_s3c2410_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
int
serial_s3c2410_startup
(
struct
uart_port
*
port
)
static
void
s3c24xx_serial_shutdown
(
struct
uart_port
*
port
)
{
struct
s3c24xx_uart_port
*
ourport
=
to_ourport
(
port
);
if
(
ourport
->
tx_claimed
)
{
free_irq
(
TX_IRQ
(
port
),
ourport
);
tx_enabled
(
port
)
=
0
;
ourport
->
tx_claimed
=
0
;
}
if
(
ourport
->
rx_claimed
)
{
free_irq
(
RX_IRQ
(
port
),
ourport
);
ourport
->
rx_claimed
=
0
;
rx_enabled
(
port
)
=
0
;
}
}
static
int
s3c24xx_serial_startup
(
struct
uart_port
*
port
)
{
struct
s3c24xx_uart_port
*
ourport
=
to_ourport
(
port
);
unsigned
long
flags
;
int
ret
;
tx_enabled
(
port
)
=
1
;
rx_enabled
(
port
)
=
1
;
dbg
(
"s3c24xx_serial_startup: port=%p (%08lx,%p)
\n
"
,
port
->
mapbase
,
port
->
membase
);
local_irq_save
(
flags
);
dbg
(
"serial_s3c2410_startup: port=%p (%p)
\n
"
,
port
,
port
->
mapbase
);
rx_enabled
(
port
)
=
1
;
ret
=
request_irq
(
RX_IRQ
(
port
),
serial_s3c2410_rx_chars
,
0
,
serial_s3c2410_name
,
port
);
ret
=
request_irq
(
RX_IRQ
(
port
),
s3c24xx_serial_rx_chars
,
0
,
s3c24xx_serial_portname
(
port
),
ourport
);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
{
printk
(
KERN_ERR
"cannot get irq %d
\n
"
,
RX_IRQ
(
port
));
return
ret
;
}
ourport
->
rx_claimed
=
1
;
dbg
(
"requesting tx irq...
\n
"
);
ret
=
request_irq
(
TX_IRQ
(
port
),
serial_s3c2410_tx_chars
,
0
,
serial_s3c2410_name
,
port
);
tx_enabled
(
port
)
=
1
;
ret
=
request_irq
(
TX_IRQ
(
port
),
s3c24xx_serial_tx_chars
,
0
,
s3c24xx_serial_portname
(
port
),
ourport
);
if
(
ret
)
{
free_irq
(
RX_IRQ
(
port
),
port
);
return
ret
;
printk
(
KERN_ERR
"cannot get irq %d
\n
"
,
TX_IRQ
(
port
)
);
goto
err
;
}
ourport
->
tx_claimed
=
1
;
dbg
(
"s3c24xx_serial_startup ok
\n
"
);
/* the port reset code should have done the correct
* register setup for the port controls */
local_irq_restore
(
flags
);
return
ret
;
err:
s3c24xx_serial_shutdown
(
port
);
local_irq_restore
(
flags
);
return
ret
;
}
static
void
serial_s3c2410_shutdown
(
struct
uart_port
*
port
)
/* power power management control */
static
void
s3c24xx_serial_pm
(
struct
uart_port
*
port
,
unsigned
int
level
,
unsigned
int
old
)
{
struct
s3c24xx_uart_port
*
ourport
=
to_ourport
(
port
);
switch
(
level
)
{
case
3
:
if
(
!
IS_ERR
(
ourport
->
baudclk
)
&&
ourport
->
baudclk
!=
NULL
)
clk_disable
(
ourport
->
baudclk
);
clk_disable
(
ourport
->
clk
);
break
;
case
0
:
clk_enable
(
ourport
->
clk
);
if
(
!
IS_ERR
(
ourport
->
baudclk
)
&&
ourport
->
baudclk
!=
NULL
)
clk_enable
(
ourport
->
baudclk
);
break
;
default:
printk
(
KERN_ERR
"s3c24xx_serial: unknown pm %d
\n
"
,
level
);
}
}
/* baud rate calculation
*
* The UARTs on the S3C2410/S3C2440 can take their clocks from a number
* of different sources, including the peripheral clock ("pclk") and an
* external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
* with a programmable extra divisor.
*
* The following code goes through the clock sources, and calculates the
* baud clocks (and the resultant actual baud rates) and then tries to
* pick the closest one and select that.
*
* NOTES:
* 1) there is no current code to properly select/deselect FCLK on
* the s3c2440, so only specify FCLK or non-FCLK in the clock
* sources for the UART
*
*/
#define MAX_CLKS (8)
static
struct
s3c24xx_uart_clksrc
tmp_clksrc
=
{
.
name
=
"pclk"
,
.
min_baud
=
0
,
.
max_baud
=
0
,
.
divisor
=
1
,
};
static
inline
int
s3c24xx_serial_getsource
(
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
*
c
)
{
struct
s3c24xx_uart_info
*
info
=
s3c24xx_port_to_info
(
port
);
return
(
info
->
get_clksrc
)(
port
,
c
);
}
static
inline
int
s3c24xx_serial_setsource
(
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
*
c
)
{
free_irq
(
TX_IRQ
(
port
),
port
);
free_irq
(
RX_IRQ
(
port
),
port
);
struct
s3c24xx_uart_info
*
info
=
s3c24xx_port_to_info
(
port
);
return
(
info
->
set_clksrc
)(
port
,
c
);
}
static
void
serial_s3c2410_set_termios
(
struct
uart_port
*
port
,
struct
termios
*
termios
,
struct
baud_calc
{
struct
s3c24xx_uart_clksrc
*
clksrc
;
unsigned
int
calc
;
unsigned
int
quot
;
struct
clk
*
src
;
};
static
int
s3c24xx_serial_calcbaud
(
struct
baud_calc
*
calc
,
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
*
clksrc
,
unsigned
int
baud
)
{
unsigned
long
rate
;
calc
->
src
=
clk_get
(
port
->
dev
,
clksrc
->
name
);
if
(
calc
->
src
==
NULL
||
IS_ERR
(
calc
->
src
))
return
0
;
rate
=
clk_get_rate
(
calc
->
src
);
calc
->
clksrc
=
clksrc
;
calc
->
quot
=
(
rate
+
(
8
*
baud
))
/
(
16
*
baud
);
calc
->
calc
=
(
rate
/
(
calc
->
quot
*
16
));
calc
->
quot
--
;
return
1
;
}
static
unsigned
int
s3c24xx_serial_getclk
(
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
**
clksrc
,
struct
clk
**
clk
,
unsigned
int
baud
)
{
struct
s3c2410_uartcfg
*
cfg
=
s3c24xx_port_to_cfg
(
port
);
struct
s3c24xx_uart_clksrc
*
clkp
;
struct
baud_calc
res
[
MAX_CLKS
];
struct
baud_calc
*
resptr
,
*
best
,
*
sptr
;
int
i
;
clkp
=
cfg
->
clocks
;
best
=
NULL
;
if
(
cfg
->
clocks_size
<
2
)
{
if
(
cfg
->
clocks_size
==
0
)
clkp
=
&
tmp_clksrc
;
s3c24xx_serial_calcbaud
(
res
,
port
,
clkp
,
baud
);
best
=
res
;
resptr
=
best
+
1
;
}
else
{
resptr
=
res
;
for
(
i
=
0
;
i
<
cfg
->
clocks_size
;
i
++
,
clkp
++
)
{
if
(
s3c24xx_serial_calcbaud
(
resptr
,
port
,
clkp
,
baud
))
resptr
++
;
}
}
/* ok, we now need to select the best clock we found */
if
(
!
best
)
{
unsigned
int
deviation
=
(
1
<<
30
)
|
((
1
<<
30
)
-
1
);
int
calc_deviation
;
for
(
sptr
=
res
;
sptr
<
resptr
;
sptr
++
)
{
printk
(
KERN_DEBUG
"found clk %p (%s) quot %d, calc %d
\n
"
,
sptr
->
clksrc
,
sptr
->
clksrc
->
name
,
sptr
->
quot
,
sptr
->
calc
);
calc_deviation
=
baud
-
sptr
->
calc
;
if
(
calc_deviation
<
0
)
calc_deviation
=
-
calc_deviation
;
if
(
calc_deviation
<
deviation
)
{
best
=
sptr
;
deviation
=
calc_deviation
;
}
}
printk
(
KERN_DEBUG
"best %p (deviation %d)
\n
"
,
best
,
deviation
);
}
printk
(
KERN_DEBUG
"selected clock %p (%s) quot %d, calc %d
\n
"
,
best
->
clksrc
,
best
->
clksrc
->
name
,
best
->
quot
,
best
->
calc
);
/* store results to pass back */
*
clksrc
=
best
->
clksrc
;
*
clk
=
best
->
src
;
return
best
->
quot
;
}
static
void
s3c24xx_serial_set_termios
(
struct
uart_port
*
port
,
struct
termios
*
termios
,
struct
termios
*
old
)
{
struct
s3c2410_uartcfg
*
cfg
=
s3c24xx_port_to_cfg
(
port
);
struct
s3c24xx_uart_port
*
ourport
=
to_ourport
(
port
);
struct
s3c24xx_uart_clksrc
*
clksrc
;
struct
clk
*
clk
;
unsigned
long
flags
;
unsigned
int
baud
,
quot
;
unsigned
int
ulcon
;
...
...
@@ -309,16 +746,34 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
termios
->
c_cflag
&=
~
(
HUPCL
|
CRTSCTS
|
CMSPAR
);
termios
->
c_cflag
|=
CLOCAL
;
/*
* We don't support BREAK character recognition.
*/
termios
->
c_iflag
&=
~
(
IGNBRK
|
BRKINT
);
/*
* Ask the core to calculate the divisor for us.
*/
baud
=
uart_get_baud_rate
(
port
,
termios
,
old
,
0
,
port
->
uartclk
/
16
);
quot
=
uart_get_divisor
(
port
,
baud
);
baud
=
uart_get_baud_rate
(
port
,
termios
,
old
,
0
,
115200
*
8
);
if
(
baud
==
38400
&&
(
port
->
flags
&
UPF_SPD_MASK
)
==
UPF_SPD_CUST
)
quot
=
port
->
custom_divisor
;
else
quot
=
s3c24xx_serial_getclk
(
port
,
&
clksrc
,
&
clk
,
baud
);
/* check to see if we need to change clock source */
if
(
ourport
->
clksrc
!=
clksrc
||
ourport
->
baudclk
!=
clk
)
{
s3c24xx_serial_setsource
(
port
,
clksrc
);
if
(
ourport
->
baudclk
!=
NULL
&&
!
IS_ERR
(
ourport
->
baudclk
))
{
clk_disable
(
ourport
->
baudclk
);
clk_unuse
(
ourport
->
baudclk
);
ourport
->
baudclk
=
NULL
;
}
clk_use
(
clk
);
clk_enable
(
clk
);
ourport
->
clksrc
=
clksrc
;
ourport
->
baudclk
=
clk
;
}
switch
(
termios
->
c_cflag
&
CSIZE
)
{
case
CS5
:
...
...
@@ -340,6 +795,9 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
break
;
}
/* preserve original lcon IR settings */
ulcon
|=
(
cfg
->
ulcon
&
S3C2410_LCON_IRM
);
if
(
termios
->
c_cflag
&
CSTOPB
)
ulcon
|=
S3C2410_LCON_STOPB
;
...
...
@@ -352,18 +810,12 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
ulcon
|=
S3C2410_LCON_PNONE
;
}
/*
if (port->fifosize)
enable_fifo()
*/
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
dbg
(
"setting ulcon to %08x
\n
"
,
ulcon
);
//dbg("<flushing output from serial>\n");
dbg
(
"setting ulcon to %08x, brddiv to %d
\n
"
,
ulcon
,
quot
);
/* set the ulcon register */
wr_regl
(
port
,
S3C2410_ULCON
,
ulcon
);
wr_regl
(
port
,
S3C2410_UBRDIV
,
quot
);
dbg
(
"uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x
\n
"
,
rd_regl
(
port
,
S3C2410_ULCON
),
...
...
@@ -400,113 +852,151 @@ serial_s3c2410_set_termios(struct uart_port *port, struct termios *termios,
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
const
char
*
s
erial_s3c2410
_type
(
struct
uart_port
*
port
)
static
const
char
*
s
3c24xx_serial
_type
(
struct
uart_port
*
port
)
{
return
port
->
type
==
PORT_S3C2410
?
"S3C2410"
:
NULL
;
switch
(
port
->
type
)
{
case
PORT_S3C2410
:
return
"S3C2410"
;
case
PORT_S3C2440
:
return
"S3C2440"
;
default:
return
NULL
;
}
}
#define MAP_SIZE (0x100)
static
void
serial_s3c2410_release_port
(
struct
uart_port
*
port
)
static
void
s3c24xx_serial_release_port
(
struct
uart_port
*
port
)
{
release_mem_region
(
port
->
mapbase
,
MAP_SIZE
);
}
static
int
serial_s3c2410_request_port
(
struct
uart_port
*
port
)
static
int
s3c24xx_serial_request_port
(
struct
uart_port
*
port
)
{
return
request_mem_region
(
port
->
mapbase
,
MAP_SIZE
,
serial_s3c2410_name
)
!=
NULL
?
0
:
-
EBUSY
;
char
*
name
=
s3c24xx_serial_portname
(
port
);
return
request_mem_region
(
port
->
mapbase
,
MAP_SIZE
,
name
)
?
0
:
-
EBUSY
;
}
static
void
serial_s3c2410_config_port
(
struct
uart_port
*
port
,
int
flags
)
static
void
s3c24xx_serial_config_port
(
struct
uart_port
*
port
,
int
flags
)
{
struct
s3c24xx_uart_info
*
info
=
s3c24xx_port_to_info
(
port
);
if
(
flags
&
UART_CONFIG_TYPE
&&
s
erial_s3c2410
_request_port
(
port
)
==
0
)
port
->
type
=
PORT_S3C2410
;
s
3c24xx_serial
_request_port
(
port
)
==
0
)
port
->
type
=
info
->
type
;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static
int
s
erial_s3c2410
_verify_port
(
struct
uart_port
*
port
,
struct
serial_struct
*
ser
)
s
3c24xx_serial
_verify_port
(
struct
uart_port
*
port
,
struct
serial_struct
*
ser
)
{
int
ret
=
0
;
struct
s3c24xx_uart_info
*
info
=
s3c24xx_port_to_info
(
port
)
;
if
(
ser
->
type
!=
PORT_UNKNOWN
&&
ser
->
type
!=
PORT_S3C2410
)
ret
=
-
EINVAL
;
if
(
ser
->
type
!=
PORT_UNKNOWN
&&
ser
->
type
!=
info
->
type
)
ret
urn
-
EINVAL
;
return
ret
;
return
0
;
}
static
struct
uart_ops
serial_s3c2410_ops
=
{
.
tx_empty
=
serial_s3c2410_tx_empty
,
.
get_mctrl
=
serial_s3c2410_get_mctrl
,
.
set_mctrl
=
serial_s3c2410_set_mctrl
,
.
stop_tx
=
serial_s3c2410_stop_tx
,
.
start_tx
=
serial_s3c2410_start_tx
,
.
stop_rx
=
serial_s3c2410_stop_rx
,
.
enable_ms
=
serial_s3c2410_enable_ms
,
.
break_ctl
=
serial_s3c2410_break_ctl
,
.
startup
=
serial_s3c2410_startup
,
.
shutdown
=
serial_s3c2410_shutdown
,
.
set_termios
=
serial_s3c2410_set_termios
,
.
type
=
serial_s3c2410_type
,
.
release_port
=
serial_s3c2410_release_port
,
.
request_port
=
serial_s3c2410_request_port
,
.
config_port
=
serial_s3c2410_config_port
,
.
verify_port
=
serial_s3c2410_verify_port
,
#ifdef CONFIG_SERIAL_S3C2410_CONSOLE
static
struct
console
s3c24xx_serial_console
;
#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
#else
#define S3C24XX_SERIAL_CONSOLE NULL
#endif
static
struct
uart_ops
s3c24xx_serial_ops
=
{
.
pm
=
s3c24xx_serial_pm
,
.
tx_empty
=
s3c24xx_serial_tx_empty
,
.
get_mctrl
=
s3c24xx_serial_get_mctrl
,
.
set_mctrl
=
s3c24xx_serial_set_mctrl
,
.
stop_tx
=
s3c24xx_serial_stop_tx
,
.
start_tx
=
s3c24xx_serial_start_tx
,
.
stop_rx
=
s3c24xx_serial_stop_rx
,
.
enable_ms
=
s3c24xx_serial_enable_ms
,
.
break_ctl
=
s3c24xx_serial_break_ctl
,
.
startup
=
s3c24xx_serial_startup
,
.
shutdown
=
s3c24xx_serial_shutdown
,
.
set_termios
=
s3c24xx_serial_set_termios
,
.
type
=
s3c24xx_serial_type
,
.
release_port
=
s3c24xx_serial_release_port
,
.
request_port
=
s3c24xx_serial_request_port
,
.
config_port
=
s3c24xx_serial_config_port
,
.
verify_port
=
s3c24xx_serial_verify_port
,
};
static
struct
uart_driver
s3c24xx_uart_drv
=
{
.
owner
=
THIS_MODULE
,
.
dev_name
=
"s3c2410_serial"
,
.
nr
=
3
,
.
cons
=
S3C24XX_SERIAL_CONSOLE
,
.
driver_name
=
S3C24XX_SERIAL_NAME
,
.
devfs_name
=
S3C24XX_SERIAL_DEVFS
,
.
major
=
S3C24XX_SERIAL_MAJOR
,
.
minor
=
S3C24XX_SERIAL_MINOR
,
};
static
struct
uart_port
serial_s3c2410_ports
[
NR_PORTS
]
=
{
{
static
struct
s3c24xx_uart_port
s3c24xx_serial_ports
[
NR_PORTS
]
=
{
[
0
]
=
{
.
port
=
{
.
lock
=
SPIN_LOCK_UNLOCKED
,
.
membase
=
0
,
.
mapbase
=
0
,
.
iotype
=
UPIO_MEM
,
.
irq
=
IRQ_S3CUART_RX0
,
.
uartclk
=
0
,
.
fifosize
=
16
,
.
ops
=
&
serial_s3c2410
_ops
,
.
ops
=
&
s3c24xx_serial
_ops
,
.
flags
=
UPF_BOOT_AUTOCONF
,
.
line
=
0
,
}
},
{
[
1
]
=
{
.
port
=
{
.
lock
=
SPIN_LOCK_UNLOCKED
,
.
membase
=
0
,
.
mapbase
=
0
,
.
iotype
=
UPIO_MEM
,
.
irq
=
IRQ_S3CUART_RX1
,
.
uartclk
=
0
,
.
fifosize
=
16
,
.
ops
=
&
serial_s3c2410
_ops
,
.
ops
=
&
s3c24xx_serial
_ops
,
.
flags
=
UPF_BOOT_AUTOCONF
,
.
line
=
1
,
}
},
#if NR_PORTS > 2
,
{
[
2
]
=
{
.
port
=
{
.
lock
=
SPIN_LOCK_UNLOCKED
,
.
membase
=
0
,
.
mapbase
=
0
,
.
iotype
=
UPIO_MEM
,
.
irq
=
IRQ_S3CUART_RX2
,
.
uartclk
=
0
,
.
fifosize
=
16
,
.
ops
=
&
serial_s3c2410
_ops
,
.
ops
=
&
s3c24xx_serial
_ops
,
.
flags
=
UPF_BOOT_AUTOCONF
,
.
line
=
2
,
}
}
#endif
};
static
int
s
erial_s3c2410
_resetport
(
struct
uart_port
*
port
,
s
tatic
int
s3c24xx_serial
_resetport
(
struct
uart_port
*
port
,
struct
s3c2410_uartcfg
*
cfg
)
{
/* ensure registers are setup */
dbg
(
"s
erial_s3c2410_resetport: port=%p (%08
x), cfg=%p
\n
"
,
dbg
(
"s
3c24xx_serial_resetport: port=%p (%08l
x), cfg=%p
\n
"
,
port
,
port
->
mapbase
,
cfg
);
wr_regl
(
port
,
S3C2410_UCON
,
cfg
->
ucon
);
...
...
@@ -520,105 +1010,429 @@ serial_s3c2410_resetport(struct uart_port *port,
return
0
;
}
/* s
erial_s3c2410_init_ports
/* s
3c24xx_serial_init_port
*
* initialise the serial ports from the machine provided initialisation
* data.
* initialise a single serial port from the platform device given
*/
static
int
s3c24xx_serial_init_port
(
struct
s3c24xx_uart_port
*
ourport
,
struct
s3c24xx_uart_info
*
info
,
struct
platform_device
*
platdev
)
{
struct
uart_port
*
port
=
&
ourport
->
port
;
struct
s3c2410_uartcfg
*
cfg
;
struct
resource
*
res
;
dbg
(
"s3c24xx_serial_init_port: port=%p, platdev=%p
\n
"
,
port
,
platdev
);
if
(
platdev
==
NULL
)
return
-
ENODEV
;
cfg
=
s3c24xx_dev_to_cfg
(
&
platdev
->
dev
);
if
(
port
->
mapbase
!=
0
)
return
0
;
if
(
cfg
->
hwport
>
3
)
return
-
EINVAL
;
/* setup info for port */
port
->
dev
=
&
platdev
->
dev
;
ourport
->
info
=
info
;
/* copy the info in from provided structure */
ourport
->
port
.
fifosize
=
info
->
fifosize
;
dbg
(
"s3c24xx_serial_init_port: %p (hw %d)...
\n
"
,
port
,
cfg
->
hwport
);
port
->
uartclk
=
1
;
if
(
cfg
->
uart_flags
&
UPF_CONS_FLOW
)
{
dbg
(
"s3c24xx_serial_init_port: enabling flow control
\n
"
);
port
->
flags
|=
UPF_CONS_FLOW
;
}
/* sort our the physical and virtual addresses for each UART */
res
=
platform_get_resource
(
platdev
,
IORESOURCE_MEM
,
0
);
if
(
res
==
NULL
)
{
printk
(
KERN_ERR
"failed to find memory resource for uart
\n
"
);
return
-
EINVAL
;
}
dbg
(
"resource %p (%lx..%lx)
\n
"
,
res
,
res
->
start
,
res
->
end
);
port
->
mapbase
=
res
->
start
;
port
->
membase
=
(
void
__iomem
*
)(
res
->
start
-
S3C2410_PA_UART
);
port
->
membase
+=
S3C2410_VA_UART
;
port
->
irq
=
platform_get_irq
(
platdev
,
0
);
ourport
->
clk
=
clk_get
(
&
platdev
->
dev
,
"uart"
);
if
(
ourport
->
clk
!=
NULL
&&
!
IS_ERR
(
ourport
->
clk
))
clk_use
(
ourport
->
clk
);
dbg
(
"port: map=%08x, mem=%08x, irq=%d, clock=%ld
\n
"
,
port
->
mapbase
,
port
->
membase
,
port
->
irq
,
port
->
uartclk
);
/* reset the fifos (and setup the uart) */
s3c24xx_serial_resetport
(
port
,
cfg
);
return
0
;
}
/* Device driver serial port probe */
static
int
probe_index
=
0
;
int
s3c24xx_serial_probe
(
struct
device
*
_dev
,
struct
s3c24xx_uart_info
*
info
)
{
struct
s3c24xx_uart_port
*
ourport
;
struct
platform_device
*
dev
=
to_platform_device
(
_dev
);
int
ret
;
dbg
(
"s3c24xx_serial_probe(%p, %p) %d
\n
"
,
_dev
,
info
,
probe_index
);
ourport
=
&
s3c24xx_serial_ports
[
probe_index
];
probe_index
++
;
dbg
(
"%s: initialising port %p...
\n
"
,
__FUNCTION__
,
ourport
);
ret
=
s3c24xx_serial_init_port
(
ourport
,
info
,
dev
);
if
(
ret
<
0
)
goto
probe_err
;
dbg
(
"%s: adding port
\n
"
,
__FUNCTION__
);
uart_add_one_port
(
&
s3c24xx_uart_drv
,
&
ourport
->
port
);
dev_set_drvdata
(
_dev
,
&
ourport
->
port
);
return
0
;
probe_err:
return
ret
;
}
int
s3c24xx_serial_remove
(
struct
device
*
_dev
)
{
struct
uart_port
*
port
=
s3c24xx_dev_to_port
(
_dev
);
if
(
port
)
uart_remove_one_port
(
&
s3c24xx_uart_drv
,
port
);
return
0
;
}
/* UART power management code */
#ifdef CONFIG_PM
int
s3c24xx_serial_suspend
(
struct
device
*
dev
,
u32
state
,
u32
level
)
{
struct
uart_port
*
port
=
s3c24xx_dev_to_port
(
dev
);
if
(
port
&&
level
==
SUSPEND_DISABLE
)
uart_suspend_port
(
&
s3c24xx_uart_drv
,
port
);
return
0
;
}
int
s3c24xx_serial_resume
(
struct
device
*
dev
,
u32
level
)
{
struct
uart_port
*
port
=
s3c24xx_dev_to_port
(
dev
);
struct
s3c24xx_uart_port
*
ourport
=
to_ourport
(
port
);
if
(
port
&&
level
==
RESUME_ENABLE
)
{
clk_enable
(
ourport
->
clk
);
s3c24xx_serial_resetport
(
port
,
s3c24xx_port_to_cfg
(
port
));
clk_disable
(
ourport
->
clk
);
uart_resume_port
(
&
s3c24xx_uart_drv
,
port
);
}
return
0
;
}
#else
#define s3c24xx_serial_suspend NULL
#define s3c24xx_serial_resume NULL
#endif
int
s3c24xx_serial_init
(
struct
device_driver
*
drv
,
struct
s3c24xx_uart_info
*
info
)
{
dbg
(
"s3c24xx_serial_init(%p,%p)
\n
"
,
drv
,
info
);
return
driver_register
(
drv
);
}
/* now comes the code to initialise either the s3c2410 or s3c2440 serial
* port information
*/
static
int
serial_s3c2410_init_ports
(
void
)
/* cpu specific variations on the serial port support */
#ifdef CONFIG_CPU_S3C2410
static
int
s3c2410_serial_setsource
(
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
*
clk
)
{
struct
uart_port
*
ptr
=
serial_s3c2410_ports
;
struct
s3c2410_uartcfg
*
cfg
=
s3c2410_uartcfgs
;
static
int
inited
=
0
;
int
i
;
unsigned
long
ucon
=
rd_regl
(
port
,
S3C2410_UCON
);
if
(
strcmp
(
clk
->
name
,
"uclk"
)
==
0
)
ucon
|=
S3C2410_UCON_UCLK
;
else
ucon
&=
~
S3C2410_UCON_UCLK
;
if
(
inited
)
wr_regl
(
port
,
S3C2410_UCON
,
ucon
);
return
0
;
inited
=
1
;
}
dbg
(
"serial_s3c2410_init_ports: initialising ports...
\n
"
);
static
int
s3c2410_serial_getsource
(
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
*
clk
)
{
unsigned
long
ucon
=
rd_regl
(
port
,
S3C2410_UCON
);
for
(
i
=
0
;
i
<
NR_PORTS
;
i
++
,
ptr
++
,
cfg
++
)
{
clk
->
divisor
=
1
;
clk
->
name
=
(
ucon
&
S3C2410_UCON_UCLK
)
?
"uclk"
:
"pclk"
;
if
(
cfg
->
hwport
>
3
)
continue
;
return
0
;
}
static
struct
s3c24xx_uart_info
s3c2410_uart_inf
=
{
.
name
=
"Samsung S3C2410 UART"
,
.
type
=
PORT_S3C2410
,
.
fifosize
=
16
,
.
rx_fifomask
=
S3C2410_UFSTAT_RXMASK
,
.
rx_fifoshift
=
S3C2410_UFSTAT_RXSHIFT
,
.
tx_fifofull
=
S3C2410_UFSTAT_TXFULL
,
.
tx_fifomask
=
S3C2410_UFSTAT_TXMASK
,
.
tx_fifoshift
=
S3C2410_UFSTAT_TXSHIFT
,
.
get_clksrc
=
s3c2410_serial_getsource
,
.
set_clksrc
=
s3c2410_serial_setsource
,
};
dbg
(
"serial_s3c2410_init_ports: port %d (hw %d)...
\n
"
,
i
,
cfg
->
hwport
);
/* device management */
if
(
cfg
->
clock
!=
NULL
)
ptr
->
uartclk
=
*
cfg
->
clock
;
static
int
s3c2410_serial_probe
(
struct
device
*
dev
)
{
return
s3c24xx_serial_probe
(
dev
,
&
s3c2410_uart_inf
);
}
switch
(
cfg
->
hwport
)
{
case
0
:
ptr
->
mapbase
=
S3C2410_PA_UART0
;
ptr
->
membase
=
(
char
*
)
S3C2410_VA_UART0
;
ptr
->
irq
=
IRQ_S3CUART_RX0
;
static
struct
device_driver
s3c2410_serial_drv
=
{
.
name
=
"s3c2410-uart"
,
.
bus
=
&
platform_bus_type
,
.
probe
=
s3c2410_serial_probe
,
.
remove
=
s3c24xx_serial_remove
,
.
suspend
=
s3c24xx_serial_suspend
,
.
resume
=
s3c24xx_serial_resume
,
};
static
inline
int
s3c2410_serial_init
(
void
)
{
return
s3c24xx_serial_init
(
&
s3c2410_serial_drv
,
&
s3c2410_uart_inf
);
}
static
inline
void
s3c2410_serial_exit
(
void
)
{
driver_unregister
(
&
s3c2410_serial_drv
);
}
#define s3c2410_uart_inf_at &s3c2410_uart_inf
#else
static
inline
int
s3c2410_serial_init
(
void
)
{
return
0
;
}
static
inline
void
s3c2410_serial_exit
(
void
)
{
}
#define s3c2410_uart_inf_at NULL
#endif
/* CONFIG_CPU_S3C2410 */
#ifdef CONFIG_CPU_S3C2440
static
int
s3c2440_serial_setsource
(
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
*
clk
)
{
unsigned
long
ucon
=
rd_regl
(
port
,
S3C2410_UCON
);
// todo - proper fclk<>nonfclk switch //
ucon
&=
~
S3C2440_UCON_CLKMASK
;
if
(
strcmp
(
clk
->
name
,
"uclk"
)
==
0
)
ucon
|=
S3C2440_UCON_UCLK
;
else
if
(
strcmp
(
clk
->
name
,
"pclk"
)
==
0
)
ucon
|=
S3C2440_UCON_PCLK
;
else
if
(
strcmp
(
clk
->
name
,
"fclk"
)
==
0
)
ucon
|=
S3C2440_UCON_FCLK
;
else
{
printk
(
KERN_ERR
"unknown clock source %s
\n
"
,
clk
->
name
);
return
-
EINVAL
;
}
wr_regl
(
port
,
S3C2410_UCON
,
ucon
);
return
0
;
}
static
int
s3c2440_serial_getsource
(
struct
uart_port
*
port
,
struct
s3c24xx_uart_clksrc
*
clk
)
{
unsigned
long
ucon
=
rd_regl
(
port
,
S3C2410_UCON
);
switch
(
ucon
&
S3C2440_UCON_CLKMASK
)
{
case
S3C2440_UCON_UCLK
:
clk
->
divisor
=
1
;
clk
->
name
=
"uclk"
;
break
;
case
1
:
ptr
->
mapbase
=
S3C2410_PA_UART1
;
ptr
->
membase
=
(
char
*
)
S3C2410_VA_UART
1
;
ptr
->
irq
=
IRQ_S3CUART_RX1
;
case
S3C2440_UCON_PCLK
:
case
S3C2440_UCON_PCLK2
:
clk
->
divisor
=
1
;
clk
->
name
=
"pclk"
;
break
;
case
2
:
ptr
->
mapbase
=
S3C2410_PA_UART2
;
ptr
->
membase
=
(
char
*
)
S3C2410_VA_UART2
;
ptr
->
irq
=
IRQ_S3CUART_RX2
;
case
S3C2440_UCON_FCLK
:
clk
->
divisor
=
7
;
/* todo - work out divisor */
clk
->
name
=
"fclk"
;
break
;
}
if
(
ptr
->
mapbase
==
0
)
continue
;
return
0
;
}
static
struct
s3c24xx_uart_info
s3c2440_uart_inf
=
{
.
name
=
"Samsung S3C2440 UART"
,
.
type
=
PORT_S3C2440
,
.
fifosize
=
64
,
.
rx_fifomask
=
S3C2440_UFSTAT_RXMASK
,
.
rx_fifoshift
=
S3C2440_UFSTAT_RXSHIFT
,
.
tx_fifofull
=
S3C2440_UFSTAT_TXFULL
,
.
tx_fifomask
=
S3C2440_UFSTAT_TXMASK
,
.
tx_fifoshift
=
S3C2440_UFSTAT_TXSHIFT
,
.
get_clksrc
=
s3c2440_serial_getsource
,
.
set_clksrc
=
s3c2440_serial_setsource
};
/* device management */
static
int
s3c2440_serial_probe
(
struct
device
*
dev
)
{
dbg
(
"s3c2440_serial_probe: dev=%p
\n
"
,
dev
);
return
s3c24xx_serial_probe
(
dev
,
&
s3c2440_uart_inf
);
}
static
struct
device_driver
s3c2440_serial_drv
=
{
.
name
=
"s3c2440-uart"
,
.
bus
=
&
platform_bus_type
,
.
probe
=
s3c2440_serial_probe
,
.
remove
=
s3c24xx_serial_remove
,
.
suspend
=
s3c24xx_serial_suspend
,
.
resume
=
s3c24xx_serial_resume
,
};
static
inline
int
s3c2440_serial_init
(
void
)
{
return
s3c24xx_serial_init
(
&
s3c2440_serial_drv
,
&
s3c2440_uart_inf
);
}
static
inline
void
s3c2440_serial_exit
(
void
)
{
driver_unregister
(
&
s3c2440_serial_drv
);
}
#define s3c2440_uart_inf_at &s3c2440_uart_inf
#else
static
inline
int
s3c2440_serial_init
(
void
)
{
return
0
;
}
static
inline
void
s3c2440_serial_exit
(
void
)
{
}
#define s3c2440_uart_inf_at NULL
#endif
/* CONFIG_CPU_S3C2440 */
/* module initialisation code */
/* reset the fifos (and setup the uart */
serial_s3c2410_resetport
(
ptr
,
cfg
);
static
int
__init
s3c24xx_serial_modinit
(
void
)
{
int
ret
;
ret
=
uart_register_driver
(
&
s3c24xx_uart_drv
);
if
(
ret
<
0
)
{
printk
(
KERN_ERR
"failed to register UART driver
\n
"
);
return
-
1
;
}
s3c2410_serial_init
();
s3c2440_serial_init
();
return
0
;
}
static
void
__exit
s3c24xx_serial_modexit
(
void
)
{
s3c2410_serial_exit
();
s3c2440_serial_exit
();
uart_unregister_driver
(
&
s3c24xx_uart_drv
);
}
module_init
(
s3c24xx_serial_modinit
);
module_exit
(
s3c24xx_serial_modexit
);
/* Console code */
#ifdef CONFIG_SERIAL_S3C2410_CONSOLE
static
struct
uart_port
*
cons_uart
;
static
int
s
erial_s3c2410
_console_txrdy
(
struct
uart_port
*
port
,
unsigned
int
ufcon
)
s
3c24xx_serial
_console_txrdy
(
struct
uart_port
*
port
,
unsigned
int
ufcon
)
{
struct
s3c24xx_uart_info
*
info
=
s3c24xx_port_to_info
(
port
);
unsigned
long
ufstat
,
utrstat
;
if
(
ufcon
&
S3C2410_UFCON_FIFOMODE
)
{
/* fifo mode - check ammount of data in fifo registers... */
ufstat
=
rd_regl
(
port
,
S3C2410_UFSTAT
);
return
S3C2410_UFCON_TXC
(
ufstat
)
<
12
;
return
(
ufstat
&
info
->
tx_fifofull
)
?
0
:
1
;
}
/* in non-fifo mode, we go and use the tx buffer empty */
utrstat
=
rd_regl
(
port
,
S3C2410_UTRSTAT
);
return
(
utrstat
&
S3C2410_UTRSTAT_TXFE
)
?
1
:
0
;
return
(
utrstat
&
S3C2410_UTRSTAT_TXE
)
?
1
:
0
;
}
static
void
s
erial_s3c2410
_console_write
(
struct
console
*
co
,
const
char
*
s
,
s
3c24xx_serial
_console_write
(
struct
console
*
co
,
const
char
*
s
,
unsigned
int
count
)
{
int
i
;
unsigned
int
ufcon
=
rd_regl
(
cons_uart
,
S3C2410_UFCON
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
while
(
!
s
erial_s3c2410
_console_txrdy
(
cons_uart
,
ufcon
))
while
(
!
s
3c24xx_serial
_console_txrdy
(
cons_uart
,
ufcon
))
barrier
();
wr_regb
(
cons_uart
,
S3C2410_UTXH
,
s
[
i
]);
if
(
s
[
i
]
==
'\n'
)
{
while
(
!
s
erial_s3c2410
_console_txrdy
(
cons_uart
,
ufcon
))
while
(
!
s
3c24xx_serial
_console_txrdy
(
cons_uart
,
ufcon
))
barrier
();
wr_regb
(
cons_uart
,
S3C2410_UTXH
,
'\r'
);
...
...
@@ -627,17 +1441,21 @@ serial_s3c2410_console_write(struct console *co, const char *s,
}
static
void
__init
s
erial_s3c2410
_get_options
(
struct
uart_port
*
port
,
int
*
baud
,
s
3c24xx_serial
_get_options
(
struct
uart_port
*
port
,
int
*
baud
,
int
*
parity
,
int
*
bits
)
{
unsigned
int
ulcon
,
ucon
,
ubrdiv
;
struct
s3c24xx_uart_clksrc
clksrc
;
struct
clk
*
clk
;
unsigned
int
ulcon
;
unsigned
int
ucon
;
unsigned
int
ubrdiv
;
unsigned
long
rate
;
ulcon
=
rd_regl
(
port
,
S3C2410_ULCON
);
ucon
=
rd_regl
(
port
,
S3C2410_UCON
);
ubrdiv
=
rd_regl
(
port
,
S3C2410_UBRDIV
);
dbg
(
"s
erial_s3c2410
_get_options: port=%p
\n
"
dbg
(
"s
3c24xx_serial
_get_options: port=%p
\n
"
"registers: ulcon=%08x, ucon=%08x, ubdriv=%08x
\n
"
,
port
,
ulcon
,
ucon
,
ubrdiv
);
...
...
@@ -669,21 +1487,53 @@ serial_s3c2410_get_options(struct uart_port *port, int *baud,
*
parity
=
'o'
;
break
;
default:
case
S3C2410_LCON_PNONE
:
default:
*
parity
=
'n'
;
}
/* now calculate the baud rate */
*
baud
=
port
->
uartclk
/
(
16
*
(
ubrdiv
+
1
));
s3c24xx_serial_getsource
(
port
,
&
clksrc
);
clk
=
clk_get
(
port
->
dev
,
clksrc
.
name
);
if
(
!
IS_ERR
(
clk
)
&&
clk
!=
NULL
)
rate
=
clk_get_rate
(
clk
);
else
rate
=
1
;
*
baud
=
rate
/
(
16
*
(
ubrdiv
+
1
));
dbg
(
"calculated baud %d
\n
"
,
*
baud
);
}
}
/* s3c24xx_serial_init_ports
*
* initialise the serial ports from the machine provided initialisation
* data.
*/
static
int
s3c24xx_serial_init_ports
(
struct
s3c24xx_uart_info
*
info
)
{
struct
s3c24xx_uart_port
*
ptr
=
s3c24xx_serial_ports
;
struct
platform_device
**
platdev_ptr
;
int
i
;
dbg
(
"s3c24xx_serial_init_ports: initialising ports...
\n
"
);
platdev_ptr
=
s3c24xx_uart_devs
;
for
(
i
=
0
;
i
<
NR_PORTS
;
i
++
,
ptr
++
,
platdev_ptr
++
)
{
s3c24xx_serial_init_port
(
ptr
,
info
,
*
platdev_ptr
);
}
return
0
;
}
static
int
__init
s
erial_s3c2410
_console_setup
(
struct
console
*
co
,
char
*
options
)
s
3c24xx_serial
_console_setup
(
struct
console
*
co
,
char
*
options
)
{
struct
uart_port
*
port
;
int
baud
=
9600
;
...
...
@@ -691,23 +1541,26 @@ serial_s3c2410_console_setup(struct console *co, char *options)
int
parity
=
'n'
;
int
flow
=
'n'
;
dbg
(
"s3c24xx_serial_console_setup: co=%p (%d), %s
\n
"
,
co
,
co
->
index
,
options
);
/* is this a valid port */
if
(
co
->
index
==
-
1
||
co
->
index
>=
NR_PORTS
)
co
->
index
=
0
;
port
=
&
s
erial_s3c2410_ports
[
co
->
index
]
;
port
=
&
s
3c24xx_serial_ports
[
co
->
index
].
port
;
/* is the port configured? */
if
(
port
->
mapbase
==
0x0
)
{
co
->
index
=
0
;
port
=
&
s
erial_s3c2410_ports
[
co
->
index
]
;
port
=
&
s
3c24xx_serial_ports
[
co
->
index
].
port
;
}
cons_uart
=
port
;
dbg
(
"s
erial_s3c2410
_console_setup: port=%p (%d)
\n
"
,
port
,
co
->
index
);
dbg
(
"s
3c24xx_serial
_console_setup: port=%p (%d)
\n
"
,
port
,
co
->
index
);
/*
* Check whether an invalid uart number has been specified, and
...
...
@@ -717,138 +1570,68 @@ serial_s3c2410_console_setup(struct console *co, char *options)
if
(
options
)
uart_parse_options
(
options
,
&
baud
,
&
parity
,
&
bits
,
&
flow
);
else
serial_s3c2410_get_options
(
port
,
&
baud
,
&
parity
,
&
bits
);
s3c24xx_serial_get_options
(
port
,
&
baud
,
&
parity
,
&
bits
);
dbg
(
"s3c24xx_serial_console_setup: baud %d
\n
"
,
baud
);
return
uart_set_options
(
port
,
co
,
baud
,
parity
,
bits
,
flow
);
}
static
struct
uart_driver
s3c2410_uart_drv
;
/* s3c24xx_serial_initconsole
*
* initialise the console from one of the uart drivers
*/
static
struct
console
s
erial_s3c2410
_console
=
static
struct
console
s
3c24xx_serial
_console
=
{
.
name
=
SERIAL_S3C2410_NAME
,
.
write
=
serial_s3c2410_console_write
,
.
name
=
S3C24XX_SERIAL_NAME
,
.
device
=
uart_console_device
,
.
setup
=
serial_s3c2410_console_setup
,
.
flags
=
CON_PRINTBUFFER
,
.
index
=
-
1
,
.
data
=
&
s3c2410_uart_drv
,
.
write
=
s3c24xx_serial_console_write
,
.
setup
=
s3c24xx_serial_console_setup
};
static
int
__init
s3c2410_console_init
(
void
)
{
dbg
(
"s3c2410_console_init:
\n
"
);
serial_s3c2410_init_ports
();
register_console
(
&
serial_s3c2410_console
);
return
0
;
}
console_initcall
(
s3c2410_console_init
);
#define SERIAL_S3C2410_CONSOLE &serial_s3c2410_console
#else
#define SERIAL_S3C2410_CONSOLE NULL
#endif
static
struct
uart_driver
s3c2410_uart_drv
=
{
.
owner
=
THIS_MODULE
,
.
driver_name
=
SERIAL_S3C2410_NAME
,
.
dev_name
=
SERIAL_S3C2410_NAME
,
.
major
=
SERIAL_S3C2410_MAJOR
,
.
minor
=
SERIAL_S3C2410_MINOR
,
.
nr
=
3
,
.
cons
=
SERIAL_S3C2410_CONSOLE
,
};
/* device driver */
static
int
s3c2410_serial_probe
(
struct
device
*
_dev
);
static
int
s3c2410_serial_remove
(
struct
device
*
_dev
);
static
struct
device_driver
s3c2410_serial_drv
=
{
.
name
=
"s3c2410-uart"
,
.
bus
=
&
platform_bus_type
,
.
probe
=
s3c2410_serial_probe
,
.
remove
=
s3c2410_serial_remove
,
.
suspend
=
NULL
,
.
resume
=
NULL
,
};
#define s3c2410_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
static
int
s3c2410_serial_probe
(
struct
device
*
_dev
)
static
int
s3c24xx_serial_initconsole
(
void
)
{
struct
platform_device
*
dev
=
to_platform_device
(
_dev
);
struct
resource
*
res
=
dev
->
resource
;
int
i
;
struct
s3c24xx_uart_info
*
info
;
struct
platform_device
*
dev
=
s3c24xx_uart_devs
[
0
];
dbg
(
"s3c24
10_serial_probe: dev=%p, _dev=%p, res=%p
\n
"
,
_dev
,
dev
,
res
);
dbg
(
"s3c24
xx_serial_initconsole
\n
"
);
for
(
i
=
0
;
i
<
dev
->
num_resources
;
i
++
,
res
++
)
if
(
res
->
flags
&
IORESOURCE_MEM
)
break
;
if
(
i
<
dev
->
num_resources
)
{
struct
uart_port
*
ptr
=
serial_s3c2410_ports
;
for
(
i
=
0
;
i
<
NR_PORTS
;
i
++
,
ptr
++
)
{
dbg
(
"s3c2410_serial_probe: ptr=%p (%08x, %08x)
\n
"
,
ptr
,
ptr
->
mapbase
,
ptr
->
membase
);
if
(
ptr
->
mapbase
!=
res
->
start
)
continue
;
/* select driver based on the cpu */
dbg
(
"s3c2410_serial_probe: got device %p: port=%p
\n
"
,
_dev
,
ptr
);
uart_add_one_port
(
&
s3c2410_uart_drv
,
ptr
);
dev_set_drvdata
(
_dev
,
ptr
);
break
;
}
if
(
dev
==
NULL
)
{
printk
(
KERN_ERR
"s3c24xx: no devices for console init
\n
"
);
return
0
;
}
if
(
strcmp
(
dev
->
name
,
"s3c2410-uart"
)
==
0
)
{
info
=
s3c2410_uart_inf_at
;
}
else
if
(
strcmp
(
dev
->
name
,
"s3c2440-uart"
)
==
0
)
{
info
=
s3c2440_uart_inf_at
;
}
else
{
printk
(
KERN_ERR
"s3c24xx: no driver for %s
\n
"
,
dev
->
name
);
return
0
;
}
static
int
s3c2410_serial_remove
(
struct
device
*
_dev
)
{
struct
uart_port
*
port
=
s3c2410_dev_to_port
(
_dev
);
if
(
port
)
uart_remove_one_port
(
&
s3c2410_uart_drv
,
port
);
}
if
(
info
==
NULL
)
{
printk
(
KERN_ERR
"s3c24xx: no driver for console
\n
"
);
return
0
;
}
static
int
__init
serial_s3c2410_init
(
void
)
{
int
ret
;
printk
(
KERN_INFO
"S3C2410X Serial, (c) 2003 Simtec Electronics
\n
"
);
ret
=
uart_register_driver
(
&
s3c2410_uart_drv
);
if
(
ret
!=
0
)
return
ret
;
ret
=
driver_register
(
&
s3c2410_serial_drv
);
if
(
ret
)
{
uart_unregister_driver
(
&
s3c2410_uart_drv
);
}
return
ret
;
}
s3c24xx_serial_console
.
data
=
&
s3c24xx_uart_drv
;
s3c24xx_serial_init_ports
(
info
);
static
void
__exit
serial_s3c2410_exit
(
void
)
{
driver_unregister
(
&
s3c2410_serial_drv
);
uart_unregister_driver
(
&
s3c2410_uart_drv
);
register_console
(
&
s3c24xx_serial_console
);
return
0
;
}
module_init
(
serial_s3c2410_init
);
module_exit
(
serial_s3c2410_exit
);
console_initcall
(
s3c24xx_serial_initconsole
);
#endif
/* CONFIG_SERIAL_S3C2410_CONSOLE */
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Ben Dooks <ben@simtec.co.uk>"
);
MODULE_DESCRIPTION
(
"Samsung S3C2410
X (S3C2410) Serial
driver"
);
MODULE_DESCRIPTION
(
"Samsung S3C2410
/S3C2440 Serial port
driver"
);
include/asm-arm/arch-s3c2410/regs-serial.h
View file @
70ca2c43
...
...
@@ -68,6 +68,12 @@
#define S3C2410_LCON_STOPB (1<<2)
#define S3C2410_LCON_IRM (1<<6)
#define S3C2440_UCON_CLKMASK (3<<10)
#define S3C2440_UCON_PCLK (0<<10)
#define S3C2440_UCON_UCLK (1<<10)
#define S3C2440_UCON_PCLK2 (2<<10)
#define S3C2440_UCON_FCLK (3<<10)
#define S3C2410_UCON_UCLK (1<<10)
#define S3C2410_UCON_SBREAK (1<<4)
...
...
@@ -77,19 +83,35 @@
#define S3C2410_UCON_RXIRQMODE (1<<0)
#define S3C2410_UCON_RXFIFO_TOI (1<<7)
#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL \
| S3C2410_UCON_TXIRQMODE | S3C2410_UCON_RXIRQMODE \
| S3C2410_UCON_RXFIFO_TOI)
#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
S3C2410_UCON_RXILEVEL | \
S3C2410_UCON_TXIRQMODE | \
S3C2410_UCON_RXIRQMODE | \
S3C2410_UCON_RXFIFO_TOI)
#define S3C2410_UFCON_FIFOMODE (1<<0)
#define S3C2410_UFCON_TXTRIG0 (0<<6)
#define S3C2410_UFCON_RXTRIG8 (1<<4)
#define S3C2410_UFCON_RXTRIG12 (2<<4)
/* S3C2440 FIFO trigger levels */
#define S3C2440_UFCON_RXTRIG1 (0<<4)
#define S3C2440_UFCON_RXTRIG8 (1<<4)
#define S3C2440_UFCON_RXTRIG16 (2<<4)
#define S3C2440_UFCON_RXTRIG32 (3<<4)
#define S3C2440_UFCON_TXTRIG0 (0<<6)
#define S3C2440_UFCON_TXTRIG16 (1<<6)
#define S3C2440_UFCON_TXTRIG32 (2<<6)
#define S3C2440_UFCON_TXTRIG48 (3<<6)
#define S3C2410_UFCON_RESETBOTH (3<<1)
#define S3C2410_UFCON_RESETTX (1<<2)
#define S3C2410_UFCON_RESETRX (1<<1)
#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | S3C2410_UFCON_TXTRIG0 \
| S3C2410_UFCON_RXTRIG8 )
#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
S3C2410_UFCON_TXTRIG0 | \
S3C2410_UFCON_RXTRIG8 )
#define S3C2410_UFSTAT_TXFULL (1<<9)
#define S3C2410_UFSTAT_RXFULL (1<<8)
...
...
@@ -111,32 +133,36 @@
#define S3C2410_UERSTAT_OVERRUN (1<<0)
#define S3C2410_UERSTAT_FRAME (1<<2)
#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | S3C2410_UERSTAT_FRAME)
#define S3C2410_UERSTAT_BREAK (1<<3)
#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \
S3C2410_UERSTAT_FRAME | \
S3C2410_UERSTAT_BREAK)
/* fifo size information */
#define S3C2410_UMSTAT_CTS (1<<0)
#define S3C2410_UMSTAT_DeltaCTS (1<<2)
#ifndef __ASSEMBLY__
static
inline
int
S3C2410_UFCON_RXC
(
int
fcon
)
{
if
(
fcon
&
S3C2410_UFSTAT_RXFULL
)
return
16
;
return
((
fcon
)
&
S3C2410_UFSTAT_RXMASK
)
>>
S3C2410_UFSTAT_RXSHIFT
;
}
static
inline
int
S3C2410_UFCON_TXC
(
int
fcon
)
{
if
(
fcon
&
S3C2410_UFSTAT_TXFULL
)
return
16
;
return
((
fcon
)
&
S3C2410_UFSTAT_TXMASK
)
>>
S3C2410_UFSTAT_TXSHIFT
;
}
#endif
/* __ASSEMBLY__ */
/* struct s3c24xx_uart_clksrc
*
* this structure defines a named clock source that can be used for the
* uart, so that the best clock can be selected for the requested baud
* rate.
*
* min_baud and max_baud define the range of baud-rates this clock is
* acceptable for, if they are both zero, it is assumed any baud rate that
* can be generated from this clock will be used.
*
* divisor gives the divisor from the clock to the one seen by the uart
*/
#define S3C2410_UMSTAT_CTS (1<<0)
#define S3C2410_UMSTAT_DeltaCTS (1<<2)
struct
s3c24xx_uart_clksrc
{
const
char
*
name
;
unsigned
int
divisor
;
unsigned
int
min_baud
;
unsigned
int
max_baud
;
};
#ifndef __ASSEMBLY__
/* configuration structure for per-machine configurations for the
* serial port
*
...
...
@@ -148,15 +174,23 @@ struct s3c2410_uartcfg {
unsigned
char
hwport
;
/* hardware port number */
unsigned
char
unused
;
unsigned
short
flags
;
unsigned
long
*
clock
;
/* pointer to clock rate */
unsigned
long
uart_flags
;
/* default uart flags */
unsigned
long
ucon
;
/* value of ucon for port */
unsigned
long
ulcon
;
/* value of ulcon for port */
unsigned
long
ufcon
;
/* value of ufcon for port */
struct
s3c24xx_uart_clksrc
*
clocks
;
unsigned
int
clocks_size
;
};
extern
struct
s3c2410_uartcfg
*
s3c2410_uartcfgs
;
/* s3c24xx_uart_devs
*
* this is exported from the core as we cannot use driver_register(),
* or platform_add_device() before the console_initcall()
*/
extern
struct
platform_device
*
s3c24xx_uart_devs
[
3
];
#endif
/* __ASSEMBLY__ */
...
...
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