1. 程式人生 > >16C2550串列埠晶片在at91sam9263板上的linux驅動移植 .

16C2550串列埠晶片在at91sam9263板上的linux驅動移植 .

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?
  1. #define ST16C2550_BASE          0x30000000  //  NCS2    //A口
  2. #define NCSx_PIN                AT91_PIN_PD11   //NCS2
  3. #define IRQ_PIN                 AT91_PIN_PA10   // IRQ3
  4. #define ST16C2550_BASE_B            0x40000000  //  NCS3    //B口
  5. #define NCSx_PIN_B              AT91_PIN_PD15   //NCS3
  6. #define IRQ_PIN_B                   AT91_PIN_PA8    // IRQ2
  7. staticstruct plat_serial8250_port st16c2550_data[] = {  
  8.         {  
  9.             .mapbase    =   ST16C2550_BASE,  
  10.             .irq            =   IRQ_PIN,  
  11.             .uartclk        =   18432000,  
  12.             .regshift       =   0,  
  13.             .iotype     =   UPIO_MEM,  
  14.             .flags      =   UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,  
  15.         },  
  16.         {  
  17.             .mapbase    =   ST16C2550_BASE_B,  
  18.             .irq            =   IRQ_PIN_B,  
  19.             .uartclk        =   18432000,  
  20.             .regshift       =   0,  
  21.             .iotype     =   UPIO_MEM,  
  22.             .flags      =   UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,  
  23.         },  
  24.         {},  
  25. };  
  26. staticstruct platform_device st16c2550_device = {  
  27.     .name   = "serial8250",  
  28.     .id         = PLAT8250_DEV_PLATFORM,  
  29.     .dev        = {  
  30.         .dma_mask = &st16c2550_dmamask,  
  31.         .coherent_dma_mask  =   DMA_BIT_MASK(32),  
  32.         .platform_data = &st16c2550_data,  
  33.     },  
  34. };  
  35. void __init at91_add_st16c2550(void)  
  36. {  
  37. staticvoid __iomem *smc_base;  
  38. /*A NCS2*/
  39. // setup NCSx pin
  40.     at91_set_A_periph(NCSx_PIN, 0);  
  41. // setup irq pin
  42.     at91_set_gpio_input(IRQ_PIN, 0);  
  43.     at91_sys_write(AT91_SMC_MODE(2),(AT91_SMC_READMODE | AT91_SMC_WRITEMODE  
  44.             | AT91_SMC_EXNWMODE_DISABLE  
  45.             | AT91_SMC_BAT_SELECT  
  46.             | AT91_SMC_DBW_8));  
  47.     at91_sys_write(AT91_SMC_CYCLE(2),0x000e000f);  
  48.     at91_sys_write(AT91_SMC_SETUP(2),0x03040304);  
  49.     at91_sys_write(AT91_SMC_PULSE(2),0x07060807);  
  50. /*B NCS3*/
  51. // setup NCSx pin
  52.     at91_set_A_periph(NCSx_PIN_B, 0);  
  53. // setup irq pin
  54.     at91_set_gpio_input(IRQ_PIN_B, 0);  
  55.     at91_sys_write(AT91_SMC_MODE(3),(AT91_SMC_READMODE | AT91_SMC_WRITEMODE  
  56.             | AT91_SMC_EXNWMODE_DISABLE  
  57.             | AT91_SMC_BAT_SELECT  
  58.             | AT91_SMC_DBW_8));  
  59.     at91_sys_write(AT91_SMC_CYCLE(3),0x000e000f);  
  60.     at91_sys_write(AT91_SMC_SETUP(3),0x03040304);  
  61.     at91_sys_write(AT91_SMC_PULSE(3),0x07060807);  
  62.     platform_device_register(&st16c2550_device);  
  63. }  
#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片選空間是否被其他外設用過。若不注意,則配置時序時後一配置覆蓋了前一配置,導致讀寫時序不正確。