linux 串口驱动(用platform与不用比较)

    #include <linux/module.h>  
    #include <linux/kernel.h>  
    #include <linux/fs.h>  
    #include <linux/errno.h>  
    #include <linux/types.h>  
    #include <linux/fcntl.h>  
    #include <linux/cdev.h>  
    #include <linux/version.h>  
    #include <linux/vmalloc.h>  
    #include <linux/ctype.h>  
    #include <linux/pagemap.h>  
    #include <linux/serial_core.h>  
      
    #include <asm/io.h>  
    #include <asm/irq.h>  
    #include <asm/signal.h>  
    #include <mach/hardware.h>  
    #include <asm/uaccess.h>  
    #include <mach/regs-gpio.h>  
    #include <plat/regs-serial.h>  
      
    #define ULCON1 (S3C24XX_VA_UART1 + S3C2410_ULCON)  //UART1映射后的地址(在 <plat/regs-serial.h>中),加上偏移地址就是相关寄存器  
    #define UCON1 (S3C24XX_VA_UART1 + S3C2410_UCON)  
    #define UFCON1 (S3C24XX_VA_UART1 + S3C2410_UFCON)  
    #define UMCON1 (S3C24XX_VA_UART1 + S3C2410_UMCON)  
    #define UBRDIV1 (S3C24XX_VA_UART1 + S3C2410_UBRDIV)  
    #define UTRSTAT1 (S3C24XX_VA_UART1 + S3C2410_UTRSTAT)  
    #define URXH1 (S3C24XX_VA_UART1 + S3C2410_URXH)  
    #define UTXH1 (S3C24XX_VA_UART1 + S3C2410_UTXH)  
      
    static int major = 0;  
      
    int uart_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)  
    {  
        char *buf = "hello world!";  
        int i = 12;  
        writel((readl(S3C2410_GPHCON)&0xff00ff), S3C2410_GPHCON);  
        writel((readl(S3C2410_GPHCON)|0x00aa00), S3C2410_GPHCON);//设置为uart1  
        writel((readl(S3C2410_GPHUP)&0xf0f), S3C2410_GPHUP);  
        writel((readl(S3C2410_GPHUP)|0x0f0), S3C2410_GPHUP); //上拉使能  
      
        writel(0x03, ULCON1); //设置串口线控制器,8数据位,1停止位  
        writel(0x0805, UCON1); //设置时钟源为PCLK,发送数据位查询方式。  
        writel(0x1a, UBRDIV1); //设置波特率为115200  
      
        while(i--)  
        {  
            while(!(readl(UTRSTAT1) & 0x02));  
                writel((int)(*(buf++)), UTXH1); //原来是直接用*(buf++)可是结果出来的是乱码,转换int后可行。  
        }  
      
        return 0;  
    }  
      
    struct file_operations uart_fops = {  
        .owner =    THIS_MODULE,  
        .ioctl =    uart_ioctl,  
    };  
      
    static int uart_init(void)  
    {  
      
      
      
        major = register_chrdev(0, "uart", &uart_fops);  
        printk("%d", major); //打印字符设备号,创建节点mknod /dev/uart 252 0  
        return 0;  
      
    }  
      
    static void uart_exit(void)  
    {  
      
        unregister_chrdev(major, "uart");  
        printk("remove modules uart.ko. please remove node\n");  
      
    }  
      
    module_init(uart_init);  
    module_exit(uart_exit);  
      
    MODULE_LICENSE("GPL");  






    #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 "samsung.h"  
      
    static int s3c6400_serial_setsource(struct uart_port *port,  
                        struct s3c24xx_uart_clksrc *clk)  
    {  
        unsigned long ucon = rd_regl(port, S3C2410_UCON);  
      
        if (strcmp(clk->name, "uclk0") == 0) {  
            ucon &= ~S3C6400_UCON_CLKMASK;  
            ucon |= S3C6400_UCON_UCLK0;  
        } else if (strcmp(clk->name, "uclk1") == 0)  
            ucon |= S3C6400_UCON_UCLK1;  
        else if (strcmp(clk->name, "pclk") == 0) {  
            /* See notes about transitioning from UCLK to PCLK */  
            ucon &= ~S3C6400_UCON_UCLK0;  
        } else {  
            printk(KERN_ERR "unknown clock source %s\n", clk->name);  
            return -EINVAL;  
        }  
      
        wr_regl(port, S3C2410_UCON, ucon);  
        return 0;  
    }  
      
      
    static int s3c6400_serial_getsource(struct uart_port *port,  
                        struct s3c24xx_uart_clksrc *clk)  
    {  
        u32 ucon = rd_regl(port, S3C2410_UCON);  
      
        clk->divisor = 1;  
      
        switch (ucon & S3C6400_UCON_CLKMASK) {  
        case S3C6400_UCON_UCLK0:  
            clk->name = "uclk0";  
            break;  
      
        case S3C6400_UCON_UCLK1:  
            clk->name = "uclk1";  
            break;  
      
        case S3C6400_UCON_PCLK:  
        case S3C6400_UCON_PCLK2:  
            clk->name = "pclk";  
            break;  
        }  
      
        return 0;  
    }  
      
    static int s3c6400_serial_resetport(struct uart_port *port,  
                        struct s3c2410_uartcfg *cfg)  
    {  
        unsigned long ucon = rd_regl(port, S3C2410_UCON);  
      
        dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",  
            port, port->mapbase, cfg);  
      
        /* ensure we don't change the clock settings... */  
      
        ucon &= S3C6400_UCON_CLKMASK;  
      
        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 s3c6400_uart_inf = {  
        .name       = "Samsung S3C6400 UART",  
        .type       = PORT_S3C6400,  
        .fifosize   = 64,  
        .has_divslot    = 1,  
        .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 = s3c6400_serial_getsource,  
        .set_clksrc = s3c6400_serial_setsource,  
        .reset_port = s3c6400_serial_resetport,  
    };  
      
    /* device management */  
      
    static int s3c6400_serial_probe(struct platform_device *dev)  
    {  
        dbg("s3c6400_serial_probe: dev=%p\n", dev);  
        return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);  
    }  
      
    static struct platform_driver s3c6400_serial_driver = {  
        .probe      = s3c6400_serial_probe,  
        .remove     = __devexit_p(s3c24xx_serial_remove),  
        .driver     = {  
            .name   = "s3c6400-uart",  
            .owner  = THIS_MODULE,  
        },  
    };  
      
    s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf);  
      
    static int __init s3c6400_serial_init(void)  
    {  
        return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf);  
    }  
      
    static void __exit s3c6400_serial_exit(void)  
    {  
        platform_driver_unregister(&s3c6400_serial_driver);  
    }  
      
    module_init(s3c6400_serial_init);  
    module_exit(s3c6400_serial_exit);  
      
    MODULE_AUTHOR("muge0913");  
    MODULE_LICENSE("GPL v2");  
    MODULE_ALIAS("platform:s3c6400-uart");  
posted @ 2013-03-14 22:44  顶顶顶顶  阅读(296)  评论(0)    收藏  举报