⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_vk32xx.c

📁 vk3x系列串口扩展芯片在linux下的SPI接口驱动源码和测试应用程序源码
💻 C
📖 第 1 页 / 共 2 页
字号:
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 + -