您的位置:首页 > 运维架构 > Linux

16C2550串口芯片在at91sam9263板上的linux驱动移植 .

2013-12-23 11:32 225 查看
16C2550串口芯片可以扩展两个串口。它的操作方法和寄存器用法与8250完全相同,因此我们可以用linux内经典的8250驱动来驱动st16c2550。

8250驱动完全不变,需要添加16C2550的初始化代码。初始化代码中要对16C2550进行片选和IRQ的管脚设置,并且要对16c2550外设的读写时序配置(setup,pulse,cycle),同时将驱动和设备挂钩。

对外设空间读写时序的配置十分重要。如果不配置或配置错误,则cpu无法识别串口芯片,或识别为16450。所以这一步十分关键。很多人都在这一步犯过错误。比如,用了cs3空间,但是配置时却配置的是cs4的寄存器。读写时序的配置参见at91sam9263 SMC章节,与之对应的是16C2550的读写时序图。

16C2550是将两个异步串口集成到一个芯片中,彼此独立。本文A口片选CS2,中断管脚AT91_PIN_PA10,B口片选CS3,中断管脚AT91_PIN_PA8。主时钟频率为198MHz(10.101ns一个时钟周期)。

Board_at91sam9263ek.c中添加的代码如下:

[cpp]
view plaincopyprint?

#define ST16C2550_BASE 0x30000000 // NCS2 //A口

#define NCSx_PIN AT91_PIN_PD11 //NCS2

#define IRQ_PIN AT91_PIN_PA10 // IRQ3

#define ST16C2550_BASE_B 0x40000000 // NCS3 //B口

#define NCSx_PIN_B AT91_PIN_PD15 //NCS3

#define IRQ_PIN_B AT91_PIN_PA8 // IRQ2

static struct plat_serial8250_port st16c2550_data[] = {
{
.mapbase = ST16C2550_BASE,
.irq = IRQ_PIN,
.uartclk = 18432000,
.regshift = 0,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
},
{
.mapbase = ST16C2550_BASE_B,
.irq = IRQ_PIN_B,
.uartclk = 18432000,
.regshift = 0,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
},
{},
};

static struct platform_device st16c2550_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.dma_mask = &st16c2550_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &st16c2550_data,
},
};

void __init at91_add_st16c2550(void)
{
static void __iomem *smc_base;
/*A NCS2*/

// setup NCSx pin
at91_set_A_periph(NCSx_PIN, 0);
// setup irq pin
at91_set_gpio_input(IRQ_PIN, 0);

at91_sys_write(AT91_SMC_MODE(2),(AT91_SMC_READMODE | AT91_SMC_WRITEMODE
| AT91_SMC_EXNWMODE_DISABLE
| AT91_SMC_BAT_SELECT
| AT91_SMC_DBW_8));
at91_sys_write(AT91_SMC_CYCLE(2),0x000e000f);
at91_sys_write(AT91_SMC_SETUP(2),0x03040304);
at91_sys_write(AT91_SMC_PULSE(2),0x07060807);

/*B NCS3*/

// setup NCSx pin
at91_set_A_periph(NCSx_PIN_B, 0);
// setup irq pin
at91_set_gpio_input(IRQ_PIN_B, 0);

at91_sys_write(AT91_SMC_MODE(3),(AT91_SMC_READMODE | AT91_SMC_WRITEMODE
| AT91_SMC_EXNWMODE_DISABLE
| AT91_SMC_BAT_SELECT
| AT91_SMC_DBW_8));
at91_sys_write(AT91_SMC_CYCLE(3),0x000e000f);
at91_sys_write(AT91_SMC_SETUP(3),0x03040304);
at91_sys_write(AT91_SMC_PULSE(3),0x07060807);

platform_device_register(&st16c2550_device);
}

#define ST16C2550_BASE			0x30000000	//	NCS2	//A口
#define NCSx_PIN				AT91_PIN_PD11	//NCS2
#define IRQ_PIN					AT91_PIN_PA10	// IRQ3
#define ST16C2550_BASE_B			0x40000000	//	NCS3	//B口
#define NCSx_PIN_B				AT91_PIN_PD15	//NCS3
#define IRQ_PIN_B					AT91_PIN_PA8	// IRQ2

static struct plat_serial8250_port st16c2550_data[] = {
{
.mapbase	=	ST16C2550_BASE,
.irq			=	IRQ_PIN,
.uartclk		=	18432000,
.regshift		=	0,
.iotype		= 	UPIO_MEM,
.flags		=	UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
},
{
.mapbase	=	ST16C2550_BASE_B,
.irq			=	IRQ_PIN_B,
.uartclk		=	18432000,
.regshift		=	0,
.iotype		= 	UPIO_MEM,
.flags		=	UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
},
{},
};

static struct platform_device st16c2550_device = {
.name	= "serial8250",
.id 		= PLAT8250_DEV_PLATFORM,
.dev		= {
.dma_mask = &st16c2550_dmamask,
.coherent_dma_mask	=	DMA_BIT_MASK(32),
.platform_data = &st16c2550_data,
},
};

void __init at91_add_st16c2550(void)
{
static void __iomem *smc_base;
/*A NCS2*/

// setup NCSx pin
at91_set_A_periph(NCSx_PIN, 0);
// setup irq pin
at91_set_gpio_input(IRQ_PIN, 0);

at91_sys_write(AT91_SMC_MODE(2),(AT91_SMC_READMODE | AT91_SMC_WRITEMODE
| AT91_SMC_EXNWMODE_DISABLE
| AT91_SMC_BAT_SELECT
| AT91_SMC_DBW_8));
at91_sys_write(AT91_SMC_CYCLE(2),0x000e000f);
at91_sys_write(AT91_SMC_SETUP(2),0x03040304);
at91_sys_write(AT91_SMC_PULSE(2),0x07060807);

/*B NCS3*/

// setup NCSx pin
at91_set_A_periph(NCSx_PIN_B, 0);
// setup irq pin
at91_set_gpio_input(IRQ_PIN_B, 0);

at91_sys_write(AT91_SMC_MODE(3),(AT91_SMC_READMODE | AT91_SMC_WRITEMODE
| AT91_SMC_EXNWMODE_DISABLE
| AT91_SMC_BAT_SELECT
| AT91_SMC_DBW_8));
at91_sys_write(AT91_SMC_CYCLE(3),0x000e000f);
at91_sys_write(AT91_SMC_SETUP(3),0x03040304);
at91_sys_write(AT91_SMC_PULSE(3),0x07060807);

platform_device_register(&st16c2550_device);
}


在ek_board_init()初始化代码中,添加 at91_add_st16c2550()即可。

在移植驱动时,特别注意CS片选空间是否被其他外设用过。若不注意,则配置时序时后一配置覆盖了前一配置,导致读写时序不正确。

转载地址:/article/1680840.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: