S3C2440驱动简析——串口驱动
时间:11-21
来源:互联网
点击:
对于驱动的学习停歇了几乎一周的时间,期间忙于补习Linux应用编程和搜索驱动、内核相关书籍,以便之后更进一步地学习。在之前友善提供的驱动例程里面,涉及的知识面非常有限,需要研究更多的驱动源码,了解更多的驱动知识,是当务之急。研究别人代码的同时,当然不忘自己也要动手练习。以下贴出串口驱动程序,并在程序里附上简要注释。
[c-sharp]
- // linux/drivers/serial/s3c2440.c
* * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs. * * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics * http://armlinux.simtec.co.uk/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - //
- #include
"linux/module.h" - #include
"linux/ioport.h" - #include
"linux/io.h" - #include
"linux/platform_device.h" - #include
"linux/init.h" - #include
"linux/serial_core.h" - #include
"linux/serial.h" - #include
"asm/irq.h" - #include
"mach/hardware.h" - #include
"plat/regs-serial.h" - #include
"mach/regs-gpio.h" - #include
"samsung.h" - static
int s3c2440_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *clk) - {
//本函数选定串口端口和时钟源 unsigned long ucon = rd_regl(port, S3C2410_UCON); //读取寄存器UCON // todo - proper fclk<>nonfclk switch. // ucon &= ~S3C2440_UCON_CLKMASK; //#define S3C2440_UCON_CLKMASK (3<10) if (strcmp(clk->name, "uclk") == 0) //选择时钟源 ucon |= S3C2440_UCON_UCLK; else if (strcmp(clk->name, "pclk") == 0) ucon |= S3C2440_UCON_PCLK; else if (strcmp(clk->name, "fclk") == 0) ucon |= S3C2440_UCON_FCLK; else { printk(KERN_ERR "unknown clock source %s/n", clk->name); return -EINVAL; } wr_regl(port, S3C2410_UCON, ucon); //把设置过的ucon写回串口控制寄存器 return 0; - }
- static
int s3c2440_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *clk) - {
//设置时钟源和对应预分频值 unsigned long ucon = rd_regl(port, S3C2410_UCON); unsigned long ucon0, ucon1, ucon2; switch (ucon & S3C2440_UCON_CLKMASK) { case S3C2440_UCON_UCLK: clk->divisor = 1; clk->name = "uclk"; break; case S3C2440_UCON_PCLK: case S3C2440_UCON_PCLK2: clk->divisor = 1; clk->name = "pclk"; break; case S3C2440_UCON_FCLK: // the fun of calculating the uart divisors on * the s3c2440 // ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON); ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON); ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON); printk("ucons: lx, lx, lx/n", ucon0, ucon1, ucon2); ucon0 &= S3C2440_UCON0_divMASK; ucon1 &= S3C2440_UCON1_divMASK; ucon2 &= S3C2440_UCON2_divMASK; if (ucon0 != 0) { clk->divisor = ucon0 >> S3C2440_UCON_divSHIFT; clk->divisor += 6; } else if (ucon1 != 0) { clk->divisor = ucon1 >> S3C2440_UCON_divSHIFT; clk->divisor += 21; } else if (ucon2 != 0) { clk->divisor = ucon2 >> S3C2440_UCON_divSHIFT; clk->divisor += 36; } else { // manual calims 44, seems to be 9 // clk->divisor = 9; } clk->name = "fclk"; break; } return 0; - }
- static
int s3c2440_serial_resetport(struct uart_port *port, struct s3c2410_uartcfg *cfg) - {
//重设串口 unsigned long ucon = rd_regl(port, S3C2410_UCON); dbg("s3c2440_serial_resetport: port=%p (lx), cfg=%p/n", port, port->mapbase, cfg); // ensure we dont change the clock settings... // ucon &= (S3C2440_UCON0_divMASK | (3<10)); wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); //重新设置寄存器UCON wr_regl(port, S3C2410_ULCON, cfg->ulcon); //重新设置寄存器ULCON // reset both fifos // wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); //重启fifo wr_regl(port, S3C2410_UFCON, cfg->ufcon); //重新设定寄存器UFCON return 0; - }
- static
struct s3c24xx_uart_info s3c2440_uart_inf = { //串口设备环境信息和提供的操作函数 .name = "Samsung S3C2440 UART", .type = PORT_S3C2440, .fifosize = 64, .rx_fifomask = S3C2440_UFSTAT_RXMASK, .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, .rx_fifofull = S3C2440_UFSTAT_RXFULL, .tx_fifofull = S3C2440_UFSTAT_TXFULL, .tx_fifomask = S3C2440_UFSTAT_TXMASK, .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, .get_clksrc = s3c2440_serial_getsource, .set_clksrc = s3c2440_serial_setsource, .reset_port = s3c2440_serial_resetport,
S3C2440驱动简析串口驱 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)