📄 serial_vk32xx.c
字号:
static void vk32xx_break_ctl(struct uart_port *port, int break_state)
{
//break operation, but there seems no such operation in vk32
}
static int vk32xx_startup(struct uart_port *port, struct uart_info *info)
{
int retval;
uint8_t gir,sier,sctlr;
//en
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "VK32xx_start_up\n");
#endif
vk3xxx_write_reg(port->iobase,VK32XX_GCR,0x01);
port->membase=(void *)info;
sier=vk3xxx_read_reg(port->iobase,VK32XX_SIER);
sier=VK32XX_TRIEN | VK32XX_RFIEN;
vk3xxx_write_reg(port->iobase,VK32XX_SIER,sier);
sctlr=vk3xxx_read_reg(port->iobase,VK32XX_SCTLR);
sctlr |= VK32XX_UTEN;
vk3xxx_write_reg(port->iobase,VK32XX_SCTLR,sctlr);
vk3xxx_write_reg(port->iobase,VK32XX_SFOCR,0xff);//initiate the fifos
vk3xxx_write_reg(port->iobase,VK32XX_SFOCR,0xfc);
/*
* Allocate the IRQ
*/
retval = request_irq(port->irq, vk32xx_int, SA_SHIRQ, "serial_vk32xx", info); //setup the interrupt hanlder ,this irq is shared
//retval = request_irq(port->irq, vk32xx_int, 0, "serial_vk32xx", info); //setup the interrupt hanlder ,this irq is shared
if (retval){
printk(KERN_ALERT "request irq error: %d\n",retval);
return retval;
}
/*
* Finally, clear and enable interrupts
*/
//enable the sub port interrupt
gir=vk3xxx_read_reg(0,VK32XX_GIR);
switch (port->iobase){
case 1:
gir|=VK32XX_U1IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
case 2:
gir|=VK32XX_U2IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
case 3:
gir|=VK32XX_U3IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
case 4:
gir|=VK32XX_U4IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
default:
printk(KERN_ERR __FUNCTION__ ": bad iobase %d\n", port->iobase);
}
udelay(100);
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "vk32xx_startup exit\n");
#endif
return 0;
}
static void vk32xx_shutdown(struct uart_port *port, struct uart_info *info)
{
uint8_t gir;
/*
* Free the interrupt
*/
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "vk32xx_shutdown\n");
#endif
free_irq(port->irq, info); //release interrupt
/*
* Disable all interrupts, port and break condition.
*/
gir=vk3xxx_read_reg(0,VK32XX_GIR);
switch (port->iobase){
case 1:
gir&=~VK32XX_U1IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
case 2:
gir&=~VK32XX_U2IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
case 3:
gir&=~VK32XX_U3IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
case 4:
gir&=~VK32XX_U4IEN;
vk3xxx_write_reg(0,VK32XX_GIR,gir);
break;
default:
printk(KERN_ERR __FUNCTION__ ": bad iobase %d\n", port->iobase);
vk3xxx_write_reg(0,VK32XX_GCR,0x40);
}
}
static void vk32xx_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
{
unsigned long flags;
uint8_t sconr,old_sier;
uint8_t sctlr,ssr;
// return ;
printk(KERN_ALERT "change_speed\n");
sconr=vk3xxx_read_reg(port->iobase,VK32XX_SCONR);
/* byte size and parity */
//cflag & CSIZE, no such op in vk32xx
if (cflag & CSTOPB)
sconr|=VK32XX_SSTPL;
else
sconr&=~VK32XX_SSTPL;
if (cflag & PARENB) {
sconr|=VK32XX_SPAEN;
if (!(cflag & PARODD)){
sconr |= VK32XX_PAM0;
sconr &= ~VK32XX_PAM1;
}
else{
sconr |= VK32XX_PAM1;
sconr &= ~VK32XX_PAM0;
}
}
else{
sconr&=~VK32XX_SPAEN;
}
/* first, disable interrupts and drain transmitter */
local_irq_save(flags);
old_sier = vk3xxx_read_reg(port->iobase,VK32XX_SIER);
vk3xxx_write_reg(port->iobase,VK32XX_SIER,old_sier&(~(VK32XX_TRIEN | VK32XX_RFIEN)));
local_irq_restore(flags);
do{
ssr = vk3xxx_read_reg(port->iobase,VK32XX_SSR);
}while (ssr & VK32XX_TXBY);
/* then, disable everything */
sctlr=vk3xxx_read_reg(port->iobase,VK32XX_SCTLR);
vk3xxx_write_reg(port->iobase,VK32XX_SCTLR,sctlr&(~VK32XX_UTEN));
/* set the parity, stop bits and data size */
vk3xxx_write_reg(port->iobase,VK32XX_SCONR,sconr);
/* set the baud rate */
//调整波特率, 可以通过printk 试验qout的数值所对应的具体波特率
printk(KERN_ALERT "pass down baud rate:%d\n",quot);
/*
clk:3686400
expect: quot:
19200 12
9600 24
1200 192
clk:3686400*2
expect: quot:
19200 24
9600 48
1200 384
*/
//恢复正常操作
vk3xxx_write_reg(port->iobase,VK32XX_SIER,old_sier);
vk3xxx_write_reg(port->iobase,VK32XX_SCTLR,sctlr|VK32XX_UTEN);
}
static const char *vk32xx_type(struct uart_port *port)
{
return port->type == PORT_VK32XX ? "vk32xx" : NULL;//this is defined in serial_core.h
}
/*
* Release the memory region(s) being used by 'port'.
*/
static void vk32xx_release_port(struct uart_port *port)
{
//no such memory region for vk32
}
/*
* Request the memory region(s) being used by 'port'.
*/
static int vk32xx_request_port(struct uart_port *port)//no such memory region needed for vk32
{
printk(KERN_ALERT "vk32xx_request_port\n");
return 0;
}
/*
* Configure/autoconfigure the port.
*/
static void vk32xx_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE && vk32xx_request_port(port) == 0)
port->type = PORT_VK32XX;
}
/*
* Verify the new serial_struct (for TIOCSSERIAL).
* The only change we allow are to the flags and type, and
* even then only between PORT_vk32xx and PORT_UNKNOWN
*/
static int vk32xx_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_VK32XX)
ret = -EINVAL;
if (port->irq != ser->irq)
ret = -EINVAL;
if (ser->io_type != SERIAL_IO_PORT)
ret = -EINVAL;
//if (port->uartclk / 16 != ser->baud_base)//这个不确定
// ret = -EINVAL;
if (port->iobase != ser->port)
ret = -EINVAL;
if (ser->hub6 != 0)
ret = -EINVAL;
return ret;
}
static struct uart_ops vk32xx_pops = {
tx_empty: vk32xx_tx_empty,
set_mctrl: vk32xx_set_mctrl,
get_mctrl: vk32xx_get_mctrl,
stop_tx: vk32xx_stop_tx,
start_tx: vk32xx_start_tx,
stop_rx: vk32xx_stop_rx,
enable_ms: vk32xx_enable_ms,
break_ctl: vk32xx_break_ctl,
startup: vk32xx_startup,
shutdown: vk32xx_shutdown,
change_speed: vk32xx_change_speed,
type: vk32xx_type,
release_port: vk32xx_release_port,
request_port: vk32xx_request_port,
config_port: vk32xx_config_port,
verify_port: vk32xx_verify_port,
};
static struct uart_port vk32xx_ports[NR_PORTS];
/*
* Setup the vk32xx serial ports. Note that we don't include the IrDA
* port here since we have our own SIR/FIR driver (see drivers/net/irda)
*
* Note also that we support "console=ttySAx" where "x" is either 0 or 1.
* Which serial port this ends up being depends on the machine you're
* running this kernel on. I'm not convinced that this is a good idea,
* but that's the way it traditionally works.
*
* Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
* used here.
*/
static void vk32xx_init_ports(void)
{
static int first = 1;
int i;
if (!first)
return;
first = 0;
for (i = 0; i < NR_PORTS; i++) {
vk32xx_ports[i].uartclk = VK_CRASTAL_CLK;//??
vk32xx_ports[i].ops = &vk32xx_pops;
vk32xx_ports[i].fifosize = 16;
vk32xx_ports[i].iobase = i;//just indentificate which port is uesd on vk chip
vk32xx_ports[i].irq = IRQ_VK32XX;
vk32xx_ports[i].iotype = SERIAL_IO_PORT;
vk32xx_ports[i].flags = ASYNC_BOOT_AUTOCONF;
}
//在这里配置VK32对应的GPIO的中断
set_external_irq(IRQ_VK32XX,EXT_LOWLEVEL,GPIO_PULLUP_DIS);
setup_spi();
}
/*
void __init vk32xx_register_uart_fns(struct vk32xx_port_fns *fns)
{
if (fns->enable_ms)
vk32xx_pops.enable_ms = fns->enable_ms;
if (fns->get_mctrl)
vk32xx_pops.get_mctrl = fns->get_mctrl;
if (fns->set_mctrl)
vk32xx_pops.set_mctrl = fns->set_mctrl;
vk32xx_open = fns->open;
vk32xx_close = fns->close;
vk32xx_pops.pm = fns->pm;
vk32xx_pops.set_wake = fns->set_wake;
}
*/
static struct uart_driver vk32xx_reg = {
owner: THIS_MODULE,
normal_major: SERIAL_VK32XX_MAJOR,
#ifdef CONFIG_DEVFS_FS
normal_name: "ttySVK%d",
callout_name: "cusVK%d",
#else
normal_name: "ttyVK",
callout_name: "cusVK",
#endif
normal_driver: &normal,
callout_major: CALLOUT_VK32XX_MAJOR,
callout_driver: &callout,
table: vk32xx_table,
termios: vk32xx_termios,
termios_locked: vk32xx_termios_locked,
minor: MINOR_START,
nr: NR_PORTS,
port: vk32xx_ports,
cons: NULL//vk32xx_CONSOLE,
};
static int __init vk32xx_serial_init(void)
{
vk32xx_init_ports();
printk(KERN_ALERT "vk32xx_serial_init()\n");
return uart_register_driver(&vk32xx_reg);
}
static void __exit vk32xx_serial_exit(void)
{
uart_unregister_driver(&vk32xx_reg);
printk(KERN_ALERT "EXIT VK32XX\n");
vk3xxx_write_reg(0,VK32XX_GCR,0x40);
}
module_init(vk32xx_serial_init);
module_exit(vk32xx_serial_exit);
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("VKIC Ltd");
MODULE_DESCRIPTION("vk32xx generic serial port driver");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -