junwei05 发表于 2013-10-21 22:52:24

关于OK335D LINUX下485驱动的问题

OK335D LINUX下485使用的是UART2和GPIO3_2配合使用实现485驱动(见原理图),按我的理解就是把串口驱动实现为458驱动无非就是在串口发送时拉高或拉低GPIO3_2引脚,发送结束时做相反操作,按时这个485驱动在启动时会初始化这个GPIO3_2脚,我在驱动源码中serial_omap_startup()、serial_omap_start_tx()和serial_omap_stop_tx这几个函数中没找到初始化或控制GPIO3_2引脚的语句,或许是我看得不够仔细,飞凌工程师可以帮我指出来吗?如果不是按我理解的这样去做,请问是如何实现这个485驱动的?附上这几个函数的源码,谢谢
static void serial_omap_start_tx(struct uart_port *port)
{
    struct uart_omap_port *up = (struct uart_omap_port *)port;
    struct circ_buf *xmit;
    unsigned int start;
    int ret = 0;

    if (!up->use_dma) {
      pm_runtime_get_sync(&up->pdev->dev);
      serial_omap_enable_ier_thri(up);
      pm_runtime_mark_last_busy(&up->pdev->dev);
      pm_runtime_put_autosuspend(&up->pdev->dev);
      return;
    }

    if (up->uart_dma.tx_dma_used)
      return;

    xmit = &up->port.state->xmit;

    if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
      pm_runtime_get_sync(&up->pdev->dev);
      ret = omap_request_dma(up->uart_dma.uart_dma_tx,
                "UART Tx DMA",
                (void *)uart_tx_dma_callback, up,
                &(up->uart_dma.tx_dma_channel));

      if (ret < 0) {
            serial_omap_enable_ier_thri(up);
            return;
      }
    }
    spin_lock(&(up->uart_dma.tx_lock));
    up->uart_dma.tx_dma_used = true;
    spin_unlock(&(up->uart_dma.tx_lock));

    start = up->uart_dma.tx_buf_dma_phys +
                (xmit->tail & (UART_XMIT_SIZE - 1));

    up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
    /*
   * It is a circular buffer. See if the buffer has wounded back.
   * If yes it will have to be transferred in two separate dma
   * transfers
   */
    if (start + up->uart_dma.tx_buf_size >=
            up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
      up->uart_dma.tx_buf_size =
            (up->uart_dma.tx_buf_dma_phys +
            UART_XMIT_SIZE) - start;

    omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
                OMAP_DMA_AMODE_CONSTANT,
                up->uart_dma.uart_base, 0, 0);
    omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
                OMAP_DMA_AMODE_POST_INC, start, 0, 0);
    omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
                OMAP_DMA_DATA_TYPE_S8,
                up->uart_dma.tx_buf_size, 1,
                OMAP_DMA_SYNC_ELEMENT,
                up->uart_dma.uart_dma_tx, 0);
    /* FIXME: Cache maintenance needed here? */
    omap_start_dma(up->uart_dma.tx_dma_channel);
}


static void serial_omap_stop_tx(struct uart_port *port)
{
    struct uart_omap_port *up = (struct uart_omap_port *)port;

    if (up->use_dma &&
      up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
      /*
         * Check if dma is still active. If yes do nothing,
         * return. Else stop dma
         */
      if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
            return;
      omap_stop_dma(up->uart_dma.tx_dma_channel);
      omap_free_dma(up->uart_dma.tx_dma_channel);
      up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
      pm_runtime_mark_last_busy(&up->pdev->dev);
      pm_runtime_put_autosuspend(&up->pdev->dev);
    }

    pm_runtime_get_sync(&up->pdev->dev);
    if (up->ier & UART_IER_THRI) {
      up->ier &= ~UART_IER_THRI;
      serial_out(up, UART_IER, up->ier);
    }

    pm_runtime_mark_last_busy(&up->pdev->dev);
    pm_runtime_put_autosuspend(&up->pdev->dev);
}

static int serial_omap_startup(struct uart_port *port)
{
    struct uart_omap_port *up = (struct uart_omap_port *)port;
    unsigned long flags = 0;
    int retval;

    /*
   * Allocate the IRQ
   */
    retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
                up->name, up);
    if (retval)
      return retval;

    dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);

    pm_runtime_get_sync(&up->pdev->dev);
    /*
   * Clear the FIFO buffers and disable them.
   * (they will be reenabled in set_termios())
   */
    serial_omap_clear_fifos(up);
    /* For Hardware flow control */
    serial_out(up, UART_MCR, UART_MCR_RTS);

    /*
   * Clear the interrupt registers.
   */
    (void) serial_in(up, UART_LSR);
    if (serial_in(up, UART_LSR) & UART_LSR_DR)
      (void) serial_in(up, UART_RX);
    (void) serial_in(up, UART_IIR);
    (void) serial_in(up, UART_MSR);

    /*
   * Now, initialize the UART
   */
    serial_out(up, UART_LCR, UART_LCR_WLEN8);
    spin_lock_irqsave(&up->port.lock, flags);
    /*
   * Most PC uarts need OUT2 raised to enable interrupts.
   */
    up->port.mctrl |= TIOCM_OUT2;
    serial_omap_set_mctrl(&up->port, up->port.mctrl);
    spin_unlock_irqrestore(&up->port.lock, flags);

    up->msr_saved_flags = 0;
    if (up->use_dma) {
      free_page((unsigned long)up->port.state->xmit.buf);
      up->port.state->xmit.buf = dma_alloc_coherent(NULL,
            UART_XMIT_SIZE,
            (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
            0);
      init_timer(&(up->uart_dma.rx_timer));
      up->uart_dma.rx_timer.function = serial_omap_rxdma_poll;
      up->uart_dma.rx_timer.data = up->port.line;
      /* Currently the buffer size is 4KB. Can increase it */
      up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
            up->uart_dma.rx_buf_size,
            (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
    }
    /*
   * Finally, enable interrupts. Note: Modem status interrupts
   * are set via set_termios(), which will be occurring imminently
   * anyway, so we don't enable them here.
   */
    up->ier = UART_IER_RLSI | UART_IER_RDI;
    serial_out(up, UART_IER, up->ier);

    /* Enable module level wake up */
    serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);

    pm_runtime_mark_last_busy(&up->pdev->dev);
    pm_runtime_put_autosuspend(&up->pdev->dev);
    up->port_activity = jiffies;
    return 0;
}


飞凌-unix 发表于 2013-10-24 16:56:39

RS485 驱动 源码路径 : drivers/tty/serial/omap-serial.c

junwei05 发表于 2013-10-24 21:05:52

飞凌-unix 发表于 2013-10-24 16:56 static/image/common/back.gif
RS485 驱动 源码路径 : drivers/tty/serial/omap-serial.c

上的几个函数就是从这个源码路径复制的!

飞凌-unix 发表于 2013-10-28 08:35:38

楼主如果你想写的是驱动程序,单单复制代码是不行的,其他的东西也要改啊,你有没有屏蔽之前的驱动啊?

阿尔巴 发表于 2013-12-10 11:09:20

飞凌-develop 发表于 2013-12-10 11:17:15

楼上朋友,正解,RS485的驱动是有“串口驱动+GPIO控制”实现的,GPIO控制部分体现在用户程序,楼主可以看一下我们的RS485测试APP,近期将发布最新测试程序,里面会含有RS485测试源码,有GPIO控制部分,如果着急需要可以联系技术服务部门,或者加我的工作QQ:2652547374.

阿尔巴 发表于 2014-8-25 17:37:26

飞凌-develop 发表于 2014-9-10 15:43:34

RS485的测试位于光盘目录:OK335xD光盘资料(A)\linux\src\test.tar.bz2 测试程序压缩包中。
页: [1]
查看完整版本: 关于OK335D LINUX下485驱动的问题