The serial port driver file is located at: linux-2.6.32.2/drivers/serial/s3c2440.c, omitting the analysis of non-key parts.
#include #include #include #include #include #include #include #include #include #include #include #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); /* todo - proper fclk<>nonfclk switch. */ ucon &= ~S3C2440_UCON_CLKMASK; 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 %sn", clk->name); return -EINVAL; } wr_regl(port, S3C2410_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: %08lx, %08lx, %08lxn", 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 (%08lx), cfg=%pn", port, port->mapbase, cfg); /* ensure we don't change the clock settings... */ ucon &= (S3C2440_UCON0_DIVMASK | (3<<10)); wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); wr_regl(port, S3C2410_ULCON, cfg->ulcon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); wr_regl(port, S3C2410_UFCON, cfg->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, }; /* device management */ static int s3c2440_serial_probe(struct platform_device *dev) { dbg("s3c2440_serial_probe: dev=%pn", dev); return s3c24xx_serial_probe(dev, &s3c2440_uart_inf); } static struct platform_driver s3c2440_serial_driver = { //这个应该就是类似于file_operation结构体 .probe = s3c2440_serial_probe, .remove = __devexit_p(s3c24xx_serial_remove), .driver = { .name = "s3c2440-uart", .owner = THIS_MODULE, }, }; s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf); static int __init s3c2440_serial_init(void) { return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf); } static void __exit s3c2440_serial_exit(void) { platform_driver_unregister(&s3c2440_serial_driver); } module_init(s3c2440_serial_init); module_exit(s3c2440_serial_exit); MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver"); MODULE_AUTHOR("Ben Dooks MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:s3c2440-uart"); 辅助理解: 1、s3c24xx_serial_init(struct platform_driver *drv, struct s3c24xx_uart_info *info) 函数 int s3c24xx_serial_init(struct platform_driver *drv, struct s3c24xx_uart_info *info) { dbg("s3c24xx_serial_init(%p,%p)n", drv, info); #ifdef CONFIG_PM drv->suspend = s3c24xx_serial_suspend; drv->resume = s3c24xx_serial_resume; #endif return platform_driver_register(drv); } 2、struct platform_driver 结构体 struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; struct platform_device_id *id_table; }; 以下部分涉及S3C2440芯片手册部分内容,附上宏的头文件 /* arch/arm/mach-s3c2410/include/mach/regs-serial.h * * From linux/include/asm-arm/hardware/serial_s3c2410.h * * Internal header file for Samsung S3C2410 serial ports (UART0-2)*/ #ifndef __ASM_ARM_REGS_SERIAL_H #define __ASM_ARM_REGS_SERIAL_H #define S3C24XX_VA_UART0 (S3C_VA_UART) #define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 ) #define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 ) #define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 ) #define S3C2410_PA_UART0 (S3C24XX_PA_UART) #define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 ) #define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 ) #define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 ) #define S3C2410_URXH (0x24) #define S3C2410_UTXH (0x20) #define S3C2410_ULCON (0x00) #define S3C2410_UCON (0x04) #define S3C2410_UFCON (0x08) #define S3C2410_UMCON (0x0C) #define S3C2410_UBRDIV (0x28) #define S3C2410_UTRSTAT (0x10) #define S3C2410_UERSTAT (0x14) #define S3C2410_UFSTAT (0x18) #define S3C2410_UMSTAT (0x1C) #define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3)) #define S3C2410_LCON_CS5 (0x0) #define S3C2410_LCON_CS6 (0x1) #define S3C2410_LCON_CS7 (0x2) #define S3C2410_LCON_CS8 (0x3) #define S3C2410_LCON_CSMASK (0x3) #define S3C2410_LCON_PNONE (0x0) #define S3C2410_LCON_PEVEN (0x5 << 3) #define S3C2410_LCON_PODD (0x4 << 3) #define S3C2410_LCON_PMASK (0x7 << 3) #define S3C2410_LCON_STOPB (1<<2) #define S3C2410_LCON_IRM (1<<6) #define S3C2440_UCON_CLKMASK (3<<10) #define S3C2440_UCON_PCLK (0<<10) #define S3C2440_UCON_UCLK (1<<10) #define S3C2440_UCON_PCLK2 (2<<10) #define S3C2440_UCON_FCLK (3<<10) #define S3C2440_UCON2_FCLK_EN (1<<15) #define S3C2440_UCON0_DIVMASK (15 << 12) #define S3C2440_UCON1_DIVMASK (15 << 12) #define S3C2440_UCON2_DIVMASK (7 << 12) #define S3C2440_UCON_DIVSHIFT (12) #define S3C2410_UCON_UCLK (1<<10) #define S3C2410_UCON_SBREAK (1<<4) #define S3C2410_UCON_TXILEVEL (1<<9) #define S3C2410_UCON_RXILEVEL (1<<8) #define S3C2410_UCON_TXIRQMODE (1<<2) #define S3C2410_UCON_RXIRQMODE (1<<0) #define S3C2410_UCON_RXFIFO_TOI (1<<7) #define S3C2443_UCON_RXERR_IRQEN (1<<6) #define S3C2443_UCON_LOOPBACK (1<<5) #define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL | S3C2410_UCON_TXIRQMODE | S3C2410_UCON_RXIRQMODE | S3C2410_UCON_RXFIFO_TOI) #define S3C2410_UFCON_FIFOMODE (1<<0) #define S3C2410_UFCON_TXTRIG0 (0<<6) #define S3C2410_UFCON_RXTRIG8 (1<<4) #define S3C2410_UFCON_RXTRIG12 (2<<4) /* S3C2440 FIFO trigger levels */ #define S3C2440_UFCON_RXTRIG1 (0<<4) #define S3C2440_UFCON_RXTRIG8 (1<<4) #define S3C2440_UFCON_RXTRIG16 (2<<4) #define S3C2440_UFCON_RXTRIG32 (3<<4) #define S3C2440_UFCON_TXTRIG0 (0<<6) #define S3C2440_UFCON_TXTRIG16 (1<<6) #define S3C2440_UFCON_TXTRIG32 (2<<6) #define S3C2440_UFCON_TXTRIG48 (3<<6) #define S3C2410_UFCON_RESETBOTH (3<<1) #define S3C2410_UFCON_RESETTX (1<<2) #define S3C2410_UFCON_RESETRX (1<<1) #define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | S3C2410_UFCON_TXTRIG0 | S3C2410_UFCON_RXTRIG8 ) #define S3C2410_UMCOM_AFC (1<<4) #define S3C2410_UMCOM_RTS_LOW (1<<0) #define S3C2410_UFSTAT_TXFULL (1<<9) #define S3C2410_UFSTAT_RXFULL (1<<8) #define S3C2410_UFSTAT_TXMASK (15<<4) #define S3C2410_UFSTAT_TXSHIFT (4) #define S3C2410_UFSTAT_RXMASK (15<<0) #define S3C2410_UFSTAT_RXSHIFT (0) /* UFSTAT S3C2443 same as S3C2440 */ #define S3C2440_UFSTAT_TXFULL (1<<14) #define S3C2440_UFSTAT_RXFULL (1<<6) #define S3C2440_UFSTAT_TXSHIFT (8) #define S3C2440_UFSTAT_RXSHIFT (0) #define S3C2440_UFSTAT_TXMASK (63<<8) #define S3C2440_UFSTAT_RXMASK (63) #define S3C2410_UTRSTAT_TXE (1<<2) #define S3C2410_UTRSTAT_TXFE (1<<1) #define S3C2410_UTRSTAT_RXDR (1<<0) #define S3C2410_UERSTAT_OVERRUN (1<<0) #define S3C2410_UERSTAT_FRAME (1<<2) #define S3C2410_UERSTAT_BREAK (1<<3) #define S3C2443_UERSTAT_PARITY (1<<1) #define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_BREAK) #define S3C2410_UMSTAT_CTS (1<<0) #define S3C2410_UMSTAT_DeltaCTS (1<<2) #ifndef __ASSEMBLY__ /* struct s3c24xx_uart_clksrc * * this structure defines a named clock source that can be used for the * uart, so that the best clock can be selected for the requested baud * rate. * * min_baud and max_baud define the range of baud-rates this clock is * acceptable for, if they are both zero, it is assumed any baud rate that * can be generated from this clock will be used. * * divisor gives the divisor from the clock to the one seen by the uart
Previous article:Friendly Arm Mini2440 Nor Flash driver design under embedded Linux
Next article:S3C2440 U-Boot transplantation--Norflash driver support-S29AL016
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- How Lucid is overtaking Tesla with smaller motors
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Three steps to govern hybrid multicloud environments
- Three steps to govern hybrid multicloud environments
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- Melexis launches ultra-low power automotive contactless micro-power switch chip
- Filter Problems
- Switching Power Supply Theory and Design
- TI Single-Cell Fuel Gauge Basic Introduction and FAQs
- RS-485 transceiver: a summer mojito
- Do you know Allegro? Learn about Allegro's latest solutions for 48V systems required for vehicle electrification and emission control
- Disassembling a small thermometer and hygrometer
- The Definitive Guide to Arduino Robotics
- Leakage current test
- Electronics Engineer Quick-Start Resources, Super Practical, Suitable for Beginners
- Are those who have seen this almost 40 years old?