16C2550串列埠晶片在at91sam9263板上的linux驅動移植 .
阿新 • • 發佈:2019-02-05
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?
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]
- #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
- staticstruct 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,
- },
- {},
- };
- staticstruct 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)
- {
- staticvoid __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片選空間是否被其他外設用過。若不注意,則配置時序時後一配置覆蓋了前一配置,導致讀寫時序不正確。