📄 clps711x.c
字号:
port->ops->set_mctrl(port, info->mctrl);
/*
* enable the port
*/
syscon = clps_readl(SYSCON(port));
syscon |= SYSCON_UARTEN;
clps_writel(syscon, SYSCON(port));
return 0;
}
static void clps711xuart_shutdown(struct uart_port *port, struct uart_info *info)
{
u_int ubrlcr, syscon;
/*
* Free the interrupt
*/
free_irq(TX_IRQ(port), info); /* TX interrupt */
free_irq(RX_IRQ(port), info); /* RX interrupt */
/*
* disable the port
*/
syscon = clps_readl(SYSCON(port));
syscon &= ~SYSCON_UARTEN;
clps_writel(syscon, SYSCON(port));
/*
* disable break condition and fifos
*/
ubrlcr = clps_readl(UBRLCR(port));
ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
clps_writel(ubrlcr, UBRLCR(port));
}
static void clps711xuart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
{
u_int ubrlcr;
unsigned long flags;
#if DEBUG
printk("clps711xuart_change_speed(cflag=0x%x, iflag=0x%x, quot=%d) called\n",
cflag, iflag, quot);
#endif
/* byte size and parity */
switch (cflag & CSIZE) {
case CS5: ubrlcr = UBRLCR_WRDLEN5; break;
case CS6: ubrlcr = UBRLCR_WRDLEN6; break;
case CS7: ubrlcr = UBRLCR_WRDLEN7; break;
default: ubrlcr = UBRLCR_WRDLEN8; break; // CS8
}
if (cflag & CSTOPB)
ubrlcr |= UBRLCR_XSTOP;
if (cflag & PARENB) {
ubrlcr |= UBRLCR_PRTEN;
if (!(cflag & PARODD))
ubrlcr |= UBRLCR_EVENPRT;
}
if (port->fifosize > 1)
ubrlcr |= UBRLCR_FIFOEN;
port->read_status_mask = UARTDR_OVERR;
if (iflag & INPCK)
port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
// if (iflag & (BRKINT | PARMRK))
// port->read_status_mask |= AMBA_UARTRSR_BE;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
if (iflag & IGNBRK) {
// port->ignore_status_mask |= AMBA_UARTRSR_BE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support).
*/
if (iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_OVERR;
}
quot -= 1;
/* first, disable everything */
save_flags(flags); cli();
clps_writel(ubrlcr | quot, UBRLCR(port));
restore_flags(flags);
}
static const char *clps711xuart_type(struct uart_port *port)
{
return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
}
/*
* Configure/autoconfigure the port.
*/
static void clps711xuart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_CLPS711X;
}
static void clps711xuart_release_port(struct uart_port *port)
{
}
static int clps711xuart_request_port(struct uart_port *port)
{
return 0;
}
static struct uart_ops clps711x_pops = {
tx_empty: clps711xuart_tx_empty,
set_mctrl: clps711xuart_set_mctrl_null,
get_mctrl: clps711xuart_get_mctrl,
stop_tx: clps711xuart_stop_tx,
start_tx: clps711xuart_start_tx,
stop_rx: clps711xuart_stop_rx,
enable_ms: clps711xuart_enable_ms,
break_ctl: clps711xuart_break_ctl,
startup: clps711xuart_startup,
shutdown: clps711xuart_shutdown,
change_speed: clps711xuart_change_speed,
type: clps711xuart_type,
config_port: clps711xuart_config_port,
release_port: clps711xuart_release_port,
request_port: clps711xuart_request_port,
};
static struct uart_port clps711x_ports[UART_NR] = {
{
iobase: SYSCON1,
irq: IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
uartclk: 3686400,
fifosize: 16,
ops: &clps711x_pops,
flags: ASYNC_BOOT_AUTOCONF,
},
{
iobase: SYSCON2,
irq: IRQ_UTXINT2, /* IRQ_URXINT2 */
uartclk: 3686400,
fifosize: 16,
ops: &clps711x_pops,
flags: ASYNC_BOOT_AUTOCONF,
}
};
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* The console_lock must be held when we get here.
*
* Note that this is called with interrupts already disabled
*/
static void clps711xuart_console_write(struct console *co, const char *s, u_int count)
{
struct uart_port *port = clps711x_ports + co->index;
unsigned int status, syscon;
int i;
/*
* Ensure that the port is enabled.
*/
syscon = clps_readl(SYSCON(port));
clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
do {
status = clps_readl(SYSFLG(port));
} while (status & SYSFLG_UTXFF);
clps_writel(s[i], UARTDR(port));
if (s[i] == '\n') {
do {
status = clps_readl(SYSFLG(port));
} while (status & SYSFLG_UTXFF);
clps_writel('\r', UARTDR(port));
}
}
/*
* Finally, wait for transmitter to become empty
* and restore the uart state.
*/
do {
status = clps_readl(SYSFLG(port));
} while (status & SYSFLG_UBUSY);
clps_writel(syscon, SYSCON(port));
}
static kdev_t clps711xuart_console_device(struct console *co)
{
return MKDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR + co->index);
}
static void __init
clps711xuart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
{
if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
u_int ubrlcr, quot;
ubrlcr = clps_readl(UBRLCR(port));
*parity = 'n';
if (ubrlcr & UBRLCR_PRTEN) {
if (ubrlcr & UBRLCR_EVENPRT)
*parity = 'e';
else
*parity = 'o';
}
if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
*bits = 7;
else
*bits = 8;
quot = ubrlcr & UBRLCR_BAUD_MASK;
*baud = port->uartclk / (16 * (quot + 1));
}
}
static int __init clps711xuart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
port = uart_get_console(clps711x_ports, UART_NR, co);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
clps711xuart_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct console clps711x_console = {
name: SERIAL_CLPS711X_NAME,
write: clps711xuart_console_write,
device: clps711xuart_console_device,
setup: clps711xuart_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
};
void __init clps711xuart_console_init(void)
{
register_console(&clps711x_console);
}
#define CLPS711X_CONSOLE &clps711x_console
#else
#define CLPS711X_CONSOLE NULL
#endif
static struct uart_driver clps711x_reg = {
#ifdef CONFIG_DEVFS_FS
normal_name: SERIAL_CLPS711X_NAME,
callout_name: CALLOUT_CLPS711X_NAME,
#else
normal_name: SERIAL_CLPS711X_NAME,
callout_name: CALLOUT_CLPS711X_NAME,
#endif
normal_major: SERIAL_CLPS711X_MAJOR,
normal_driver: &normal,
callout_major: CALLOUT_CLPS711X_MAJOR,
callout_driver: &callout,
table: clps711x_table,
termios: clps711x_termios,
termios_locked: clps711x_termios_locked,
minor: SERIAL_CLPS711X_MINOR,
nr: UART_NR,
port: clps711x_ports,
cons: CLPS711X_CONSOLE,
};
static int __init clps711xuart_init(void)
{
return uart_register_driver(&clps711x_reg);
}
static void __exit clps711xuart_exit(void)
{
uart_unregister_driver(&clps711x_reg);
}
module_init(clps711xuart_init);
module_exit(clps711xuart_exit);
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Deep Blue Solutions Ltd");
MODULE_DESCRIPTION("CLPS-711x generic serial driver");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -