openwrt mtk7628n 如何添加uart2驱动

一、kernel配置

#make kernel_menuconfig         

添加/dev/ttyS2设备(原来只有ttyS0, ttyS1)

Device Drivers  ---> 

Character devices  --->

Serial drivers  --->

  1. Number of 8250/16550 serial ports to register at runtime

 

 

二、配置GPIO1 MODE寄存器,把相关复用io口配置为uart功能。

linux-xxx/drivers/char/ralink_gpio.c

mtk7628nn为例

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/drivers/char/ralink_gpio.c

 

ralink_gpio_init()

{

gpiomode |= RALINK_GPIOMODE_DFT;

  gpiomode &= ~0xf000000; 

*(volatile u32 *)(RALINK_REG_GPIOMODE) = cpu_to_le32(gpiomode);

}

 

三、配置串口

根据MT7628_ProgrammingGuide_20140428(E2).pdf编程指南

#vi linux-xxx/arch/mips/ralink/init.c

build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/arch/mips/ralink/init.c

serial_init(57600);

prom_init_serial_port();

 

添加uart2初始化配置:

serial_setbrg()

{

#if defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628)

        IER(RALINK_SYSCTL_BASE + 0xD00) = 0;

        FCR(RALINK_SYSCTL_BASE + 0xD00) = 0;

        LCR(RALINK_SYSCTL_BASE + 0xD00) = (UART_LCR_WLEN8 | UART_LCR_DLAB);

        DLL(RALINK_SYSCTL_BASE + 0xD00) = clock_divisor & 0xff;

        DLM(RALINK_SYSCTL_BASE + 0xD00) = clock_divisor >> 8;

        LCR(RALINK_SYSCTL_BASE + 0xD00) = UART_LCR_WLEN8;

        

      IER(RALINK_SYSCTL_BASE + 0xE00) = 0;

      FCR(RALINK_SYSCTL_BASE + 0xE00) = 0;

     LCR(RALINK_SYSCTL_BASE + 0xE00) = (UART_LCR_WLEN8 | UART_LCR_DLAB);

      DLL(RALINK_SYSCTL_BASE + 0xE00) = clock_divisor & 0xff;

      DLM(RALINK_SYSCTL_BASE + 0xE00) = clock_divisor >> 8;

      LCR(RALINK_SYSCTL_BASE + 0xE00) = UART_LCR_WLEN8;

#else

static struct uart_port serial_req[3];

prom_init_serial_port()

{

memset(serial_req, 0, 3*sizeof(struct uart_port));

~

~

~

~

serial_req[1].membase    = ioremap_nocache(RALINK_UART_LITE_BASE, PAGE_SIZE);

 

#if defined CONFIG_RALINK_MT7628

      serial_req[2].type    = PORT_16550A;

     serial_req[2].line    = 2;

       serial_req[2].irq     = SURFBOARDINT_UART_LITE3;

      serial_req[2].flags   = UPF_FIXED_TYPE;

      serial_req[2].uartclk         = 40000000;

       serial_req[2].iotype  = UPIO_MEM32;

       serial_req[2].regshift        = 2;

       serial_req[2].mapbase         = RALINK_UART_LITE3_BASE;

      serial_req[2].membase         = ioremap_nocache(RALINK_UART_LITE3_BASE, PAGE_SIZE);

#endif  

 

  early_serial_setup(&serial_req[0]);

  early_serial_setup(&serial_req[1]);

 early_serial_setup(&serial_req[2]);

  return(0);

}

四、linux  应用层开发

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<assert.h>
#include<termios.h>
#include<string.h>
#include<sys/time.h>
#include<sys/types.h>
#include<errno.h>

#define DEV_NAME  "/dev/ttyS2"
 
//设置串口波特率
static void set_baudrate (struct termios *opt, unsigned int baudrate)
{
    cfsetispeed(opt, baudrate);
    cfsetospeed(opt, baudrate);
}

//设置数据位
static void set_data_bit (struct termios *opt, unsigned int databit)
{
    opt->c_cflag &= ~CSIZE;
    switch (databit) {
    case 8:
        opt->c_cflag |= CS8;
        break;
    case 7:
        opt->c_cflag |= CS7;
        break;
    case 6:
        opt->c_cflag |= CS6;
        break;
    case 5:
        opt->c_cflag |= CS5;
        break;
    default:
        opt->c_cflag |= CS8;
        break;
    }
}

//设置校验位
static void set_parity (struct termios *opt, char parity)
{
    switch (parity) {
    case 'N':                  /* no parity check */
        opt->c_cflag &= ~PARENB;
        break;
    case 'E':                  /* even */
        opt->c_cflag |= PARENB;
        opt->c_cflag &= ~PARODD;
        break;
    case 'O':                  /* odd */
        opt->c_cflag |= PARENB;
        opt->c_cflag |= ~PARODD;
        break;
    default:                   /* no parity check */
        opt->c_cflag &= ~PARENB;
        break;
    }
}

//设置停止位
static void set_stopbit (struct termios *opt, const char *stopbit)
{
    if (0 == strcmp (stopbit, "1")) {
        opt->c_cflag &= ~CSTOPB; /* 1 stop bit */
    }    else if (0 == strcmp (stopbit, "1")) {
        opt->c_cflag &= ~CSTOPB; /* 1.5 stop bit */
    }   else if (0 == strcmp (stopbit, "2")) {
        opt->c_cflag |= CSTOPB;  /* 2 stop bits */
    } else {
        opt->c_cflag &= ~CSTOPB; /* 1 stop bit */
    }
}
//串口设置
int  set_port_attr (
              int fd,
              int  baudrate,          // B1200 B2400 B4800 B9600 .. B115200
              int  databit,           // 5, 6, 7, 8
              const char *stopbit,    //  "1", "1.5", "2"
              char parity,            // N(o), O(dd), E(ven)
              int vtime,
              int vmin )
{
     struct termios opt;
     tcgetattr(fd, &opt);
     //设置波特率
     set_baudrate(&opt, baudrate);
     opt.c_cflag          |= CLOCAL | CREAD;      /* | CRTSCTS */
     //设置数据位
     set_data_bit(&opt, databit);
     //设置校验位
     set_parity(&opt, parity);
     //设置停止位
     set_stopbit(&opt, stopbit);
     //其它设置
     opt.c_oflag          = 0;
     opt.c_lflag                |= 0;
     opt.c_oflag              &= ~OPOST;
     opt.c_cc[VTIME]          = vtime;
     opt.c_cc[VMIN]              = vmin;
     tcflush (fd, TCIFLUSH);
     return (tcsetattr (fd, TCSANOW, &opt));
}

int main(void)
{
    int fd;
    int len;
    char buf[] = "hello ZLG111111!";
    int ret;
 
 
    fd = open(DEV_NAME, O_RDWR | O_NOCTTY);
    if(fd < 0) {
            perror(DEV_NAME);
            return -1;
    }

    ret = set_port_attr(fd,B115200,8,"1",'N',150,255);
    if(ret < 0){
        printf("set_port_attr error \n");
        return -1;
    }
 
    len = write(fd, buf, sizeof(buf));
    if (len < 0) {
        printf("write data error \n");
    }
    
    len = read(fd, buf, sizeof(buf));
    if (len < 0) {
            printf("read error \n");
            return -1;
    }
 
    printf("%s", buf);
 
    return (0);
}

五、参考文献

【开发指南】M6G2C&A6G2C系列核心板软件开发指南_V1.05 (1) 第十六章串口编程

   下载地址

     https://download.csdn.net/download/caofengtao1314/10920404

猜你喜欢

转载自blog.csdn.net/caofengtao1314/article/details/86505411