Using RS485 in the serial ports

1,783 views
Skip to first unread message

Iñaki Zuloaga Izaguirre

unread,
Nov 2, 2011, 3:59:05 PM11/2/11
to Beagle Board
I have been reading the documentation for the TI microprocessors and I
haven't been able to figure out if the serial ports can be used for
RS485. It seems to me that there is no integrated support for RS485
Transmit enable generation, has anybody tried this? You can always
control the enable with a digital output, but it is very difficult to
accurately disable the Transmit enable after transmission ends.
Microprocessors from other companies like the AT91SAM9260 and LPC1768
directly support handling the RS485 enable.

Gerald Coley

unread,
Nov 2, 2011, 4:03:08 PM11/2/11
to beagl...@googlegroups.com
Yes, You will need a direction pin, such as RTS, to switch the direction on the transecier. It is all serial data. TX and RX to the driver.
 
Gerald

2011/11/2 Iñaki Zuloaga Izaguirre <ina...@gmail.com>

--
You received this message because you are subscribed to the Google Groups "Beagle Board" group.
To post to this group, send email to beagl...@googlegroups.com.
To unsubscribe from this group, send email to beagleboard...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/beagleboard?hl=en.


lexdup...@gmail.com

unread,
Apr 29, 2014, 10:24:49 AM4/29/14
to beagl...@googlegroups.com

Yes you can use the serial ports for RS485. You will need a UART to RS485 IC to get the correct voltages. RS485 is a half duplex standard and therefore has to have a directional pin. This pin can be selected to be any of the GPIO pins of the Beaglebone Black. Use the UART cape in the device tree overly to enable the serial port and then pass the RS485 stucture along with the termios information to setup the port. The structure can be found in serial.h. If you are planning to use the Modbus protocol over the RS485 network then you need to make a slight change to the libmodbus source code. In the file modbus-rtu.c there is a function called modbus_rtu_set_serial_mode. In the passing argument for the function include an additional variable int GPIO for the directional pin. In the firs if statement change the code so that it will now pass the structure of the RS485 to the port along with the directional pin. Note that you are using the patched serial.h that comes with the Debian Image for the Beaglebone Black and not the serial.h that comes as standard with Debian. After this setup the normal reading and writing functions of the Modbus library can be used

Micka

unread,
Apr 29, 2014, 10:49:19 AM4/29/14
to beagl...@googlegroups.com
For your information, there is also a RS485 Cap that is working very well . As he said : " pass the RS485 stucture along with the termios information to setup the port "


--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

cecco

unread,
May 2, 2014, 3:11:12 PM5/2/14
to beagl...@googlegroups.com, lexdup...@gmail.com
Hello,
I'm trying to set-up TxEnable (other gpio for RTS) in rs485 of my custom cape with Device Tree from weeks: all works fine, except RTS!
I use 14_04_2014 Debian image and libmodbus 3.1.1 .
can you explain me better what I have to do?
I haven’t find a complete guide for how to set-up  rs485 pin (not uart physical line!) in Device tree, only suggestion...
I'm not sure that my kernel (3.8.47) supports RS485 controls pin...

I haven't understand how modify  modbus_rtu_set_serial_mode function. Finally: must I set my custom RTS pin in device tree structure (half unknown) or in modbus_rtu_set_serial_mode function? or both?

I am sure that it was not clear... but if Yuo or someone can help me... I'm very grateful!!!

Thanks in advance!

Francesco.

lexdup...@gmail.com

unread,
May 28, 2014, 3:38:55 AM5/28/14
to beagl...@googlegroups.com, lexdup...@gmail.com

Sorry for taking so long to come back but was a bit busy. It looks like the RS 485 patch is not included in the standard Debian release for the Beaglebone Black (with all the other patches that is included). So if you are using Debian on the Beaglebone Black you have to apply the RS 485 patch of Mickae1 manually before compiling else you could replace /kernel/drivers/tty/serial/omap-serial.c with the code at the end and also replace /kernel/uapi/linux/serial.h with the code at the end and recompile. Then just pass the structure as discussed above. Make these changes before applying the additional patches for the Debian image.

 

omap-serial.c

/*

 * Driver for OMAP-UART controller.

 * Based on drivers/serial/8250.c

 *

 * Copyright (C) 2010 Texas Instruments.

 *

 * Authors:

 *          Govindraj R       <govindr...@ti.com>

 *          Thara Gopinath  <th...@ti.com>

 *

 * This program is free software; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License as published by

 * the Free Software Foundation; either version 2 of the License, or

 * (at your option) any later version.

 *

 * Note: This driver is made separate from 8250 driver as we cannot

 * over load 8250 driver with omap platform specific configuration for

 * features like DMA, it makes easier to implement features like DMA and

 * hardware flow control and software flow control configuration with

 * this driver as required for the omap-platform.

 */

 

#if defined(CONFIG_SERIAL_OMAP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)

#define SUPPORT_SYSRQ

#endif

 

#include <linux/module.h>

#include <linux/init.h>

#include <linux/console.h>

#include <linux/serial_reg.h>

#include <linux/delay.h>

#include <linux/slab.h>

#include <linux/tty.h>

#include <linux/tty_flip.h>

#include <linux/platform_device.h>

#include <linux/io.h>

#include <linux/clk.h>

#include <linux/serial_core.h>

#include <linux/irq.h>

#include <linux/pm_runtime.h>

#include <linux/of.h>

#include <linux/gpio.h>

#include <linux/uaccess.h>

#include <linux/pinctrl/consumer.h>

#include <linux/platform_data/serial-omap.h>

 

#define OMAP_MAX_HSUART_PORTS  6

 

#define UART_BUILD_REVISION(x, y)    (((x) << 8) | (y))

 

#define OMAP_UART_REV_42 0x0402

#define OMAP_UART_REV_46 0x0406

#define OMAP_UART_REV_52 0x0502

#define OMAP_UART_REV_63 0x0603

 

#define UART_ERRATA_i202_MDR1_ACCESS   BIT(0)

#define UART_ERRATA_i291_DMA_FORCEIDLE            BIT(1)

 

#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/

 

/* SCR register bitmasks */

#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK              (1 << 7)

#define OMAP_UART_SCR_TX_EMPTY                         (1 << 3)

 

/* FCR register bitmasks */

#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK                                (0x3 << 6)

#define OMAP_UART_FCR_TX_FIFO_TRIG_MASK                                 (0x3 << 4)

 

/* MVR register bitmasks */

#define OMAP_UART_MVR_SCHEME_SHIFT     30

 

#define OMAP_UART_LEGACY_MVR_MAJ_MASK        0xf0

#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT         4

#define OMAP_UART_LEGACY_MVR_MIN_MASK         0x0f

 

#define OMAP_UART_MVR_MAJ_MASK                       0x700

#define OMAP_UART_MVR_MAJ_SHIFT                        8

#define OMAP_UART_MVR_MIN_MASK                        0x3f

 

#define OMAP_UART_DMA_CH_FREE  -1

 

#define MSR_SAVE_FLAGS                  UART_MSR_ANY_DELTA

#define OMAP_MODE13X_SPEED        230400

 

/* WER = 0x7F

 * Enable module level wakeup in WER reg

 */

#define OMAP_UART_WER_MOD_WKUP          0X7F

 

/* Enable XON/XOFF flow control on output */

#define OMAP_UART_SW_TX               0x08

 

/* Enable XON/XOFF flow control on input */

#define OMAP_UART_SW_RX               0x02

 

#define OMAP_UART_SW_CLR 0xF0

 

#define OMAP_UART_TCR_TRIG           0x0F

 

struct uart_omap_dma {

            u8                                 uart_dma_tx;

            u8                                 uart_dma_rx;

            int                                 rx_dma_channel;

            int                                 tx_dma_channel;

            dma_addr_t                  rx_buf_dma_phys;

            dma_addr_t                  tx_buf_dma_phys;

            unsigned int                  uart_base;

            /*

             * Buffer for rx dma.It is not required for tx because the buffer

             * comes from port structure.

             */

            unsigned char               *rx_buf;

            unsigned int                  prev_rx_dma_pos;

            int                                 tx_buf_size;

            int                                 tx_dma_used;

            int                                 rx_dma_used;

            spinlock_t                     tx_lock;

            spinlock_t                     rx_lock;

            /* timer to poll activity on rx dma */

            struct timer_list  rx_timer;

            unsigned int                  rx_buf_size;

            unsigned int                  rx_poll_rate;

            unsigned int                  rx_timeout;

};

 

struct uart_omap_port {

            struct uart_port  port;

            struct uart_omap_dma   uart_dma;

            struct device                 *dev;

 

            unsigned char               ier;

            unsigned char               lcr;

            unsigned char               mcr;

            unsigned char               fcr;

            unsigned char               efr;

            unsigned char               dll;

            unsigned char               dlh;

            unsigned char               mdr1;

            unsigned char               scr;

 

            int                                 use_dma;

            /*

             * Some bits in registers are cleared on a read, so they must

             * be saved whenever the register is read but the bits will not

             * be immediately processed.

             */

            unsigned int                  lsr_break_flag;

            unsigned char               msr_saved_flags;

            char                              name[20];

            unsigned long               port_activity;

            int                                 context_loss_cnt;

            u32                               errata;

            u8                                 wakeups_enabled;

 

            int                                 DTR_gpio;

            int                                 DTR_inverted;

            int                                 DTR_active;

 

            struct pm_qos_request  pm_qos_request;

            u32                               latency;

            u32                               calc_latency;

            struct work_struct          qos_work;

            struct pinctrl                  *pins;

            struct serial_rs485         rs485;

};

 

#define to_uart_omap_port(p)    ((container_of((p), struct uart_omap_port, port)))

 

static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];

 

/* Forward declaration of functions */

static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);

 

static struct workqueue_struct *serial_omap_uart_wq;

 

static inline unsigned int serial_in(struct uart_omap_port *up, int offset)

{

            offset <<= up->port.regshift;

            return readw(up->port.membase + offset);

}

 

static inline void serial_out(struct uart_omap_port *up, int offset, int value)

{

            offset <<= up->port.regshift;

            writew(value, up->port.membase + offset);

}

 

static inline void serial_omap_clear_fifos(struct uart_omap_port *up)

{

            serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);

            serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |

                               UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);

            serial_out(up, UART_FCR, 0);

}

 

static int serial_omap_get_context_loss_count(struct uart_omap_port *up)

{

            struct omap_uart_port_info *pdata = up->dev->platform_data;

 

            if (!pdata || !pdata->get_context_loss_count)

                        return 0;

 

            return pdata->get_context_loss_count(up->dev);

}

 

static void serial_omap_set_forceidle(struct uart_omap_port *up)

{

            struct omap_uart_port_info *pdata = up->dev->platform_data;

 

            if (!pdata || !pdata->set_forceidle)

                        return;

 

            pdata->set_forceidle(up->dev);

}

 

static void serial_omap_set_noidle(struct uart_omap_port *up)

{

            struct omap_uart_port_info *pdata = up->dev->platform_data;

 

            if (!pdata || !pdata->set_noidle)

                        return;

 

            pdata->set_noidle(up->dev);

}

 

static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)

{

            struct omap_uart_port_info *pdata = up->dev->platform_data;

 

            if (!pdata || !pdata->enable_wakeup)

                        return;

 

            pdata->enable_wakeup(up->dev, enable);

}

 

/*

 * serial_omap_get_divisor - calculate divisor value

 * @port: uart port info

 * @baud: baudrate for which divisor needs to be calculated.

 *

 * We have written our own function to get the divisor so as to support

 * 13x mode. 3Mbps Baudrate as an different divisor.

 * Reference OMAP TRM Chapter 17:

 * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates

 * referring to oversampling - divisor value

 * baudrate 460,800 to 3,686,400 all have divisor 13

 * except 3,000,000 which has divisor value 16

 */

static unsigned int

serial_omap_get_divisor(struct uart_port *port, unsigned int baud)

{

            unsigned int divisor;

 

            if (baud > OMAP_MODE13X_SPEED && baud != 3000000)

                        divisor = 13;

            else

                        divisor = 16;

            return port->uartclk/(baud * divisor);

}

 

static void serial_omap_enable_ms(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

 

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

 

            pm_runtime_get_sync(up->dev);

            up->ier |= UART_IER_MSI;

            serial_out(up, UART_IER, up->ier);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

static inline void wait_for_xmitr(struct uart_omap_port *up);

 

static void serial_omap_stop_tx(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            int val;

            pm_runtime_get_sync(up->dev);

            if (up->ier & UART_IER_THRI) {

                        up->ier &= ~UART_IER_THRI;

                        serial_out(up, UART_IER, up->ier);

            }

 

            serial_omap_set_forceidle(up);

 

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

            wait_for_xmitr(up);

            if (up->rs485.flags & SER_RS485_ENABLED) {

                        if(up->rs485.delay_rts_after_send>0) {

                                    udelay(up->rs485.delay_rts_after_send);

                        }

                        /* Disable RS485 TX EN */

                        val = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;

                        gpio_set_value(up->rs485.gpio_pin, val);

            }

}

 

static void serial_omap_stop_rx(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

 

            pm_runtime_get_sync(up->dev);

            up->ier &= ~UART_IER_RLSI;

            up->port.read_status_mask &= ~UART_LSR_DR;

            serial_out(up, UART_IER, up->ier);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

 

static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)

{

            struct circ_buf *xmit = &up->port.state->xmit;

            int count;

 

            if (!(lsr & UART_LSR_THRE))

                        return;

 

            if (up->port.x_char) {

                        serial_out(up, UART_TX, up->port.x_char);

                        up->port.icount.tx++;

                        up->port.x_char = 0;

                        return;

            }

            if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {

                        serial_omap_stop_tx(&up->port);

                        return;

            }

            count = up->port.fifosize / 4;

            do {

                        serial_out(up, UART_TX, xmit->buf[xmit->tail]);

                        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);

                        up->port.icount.tx++;

                        if (uart_circ_empty(xmit))

                                    break;

            } while (--count > 0);

 

            if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {

                        spin_unlock(&up->port.lock);

                        uart_write_wakeup(&up->port);

                        spin_lock(&up->port.lock);

            }

 

            if (uart_circ_empty(xmit))

                        serial_omap_stop_tx(&up->port);

}

 

static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)

{

            if (!(up->ier & UART_IER_THRI)) {

                        up->ier |= UART_IER_THRI;

                        serial_out(up, UART_IER, up->ier);

            }

}

 

static void serial_omap_start_tx(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            int val;

 

            if (up->rs485.flags & SER_RS485_ENABLED) {

                        /* Enable RS485 TX EN */

                        val = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 0 : 1;

                        gpio_set_value(up->rs485.gpio_pin, val);

 

                        if(up->rs485.delay_rts_before_send>0)

                                    udelay(up->rs485.delay_rts_before_send);

            }

 

            pm_runtime_get_sync(up->dev);

            serial_omap_enable_ier_thri(up);

            serial_omap_set_noidle(up);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

 

static void serial_omap_throttle(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned long flags;

 

            pm_runtime_get_sync(up->dev);

            spin_lock_irqsave(&up->port.lock, flags);

            up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);

            serial_out(up, UART_IER, up->ier);

            spin_unlock_irqrestore(&up->port.lock, flags);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

 

static void serial_omap_unthrottle(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned long flags;

 

            pm_runtime_get_sync(up->dev);

            spin_lock_irqsave(&up->port.lock, flags);

            up->ier |= UART_IER_RLSI | UART_IER_RDI;

            serial_out(up, UART_IER, up->ier);

            spin_unlock_irqrestore(&up->port.lock, flags);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

 

static unsigned int check_modem_status(struct uart_omap_port *up)

{

            unsigned int status;

 

            status = serial_in(up, UART_MSR);

            status |= up->msr_saved_flags;

            up->msr_saved_flags = 0;

            if ((status & UART_MSR_ANY_DELTA) == 0)

                        return status;

 

            if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&

                up->port.state != NULL) {

                        if (status & UART_MSR_TERI)

                                    up->port.icount.rng++;

                        if (status & UART_MSR_DDSR)

                                    up->port.icount.dsr++;

                        if (status & UART_MSR_DDCD)

                                    uart_handle_dcd_change

                                                (&up->port, status & UART_MSR_DCD);

                        if (status & UART_MSR_DCTS)

                                    uart_handle_cts_change

                                                (&up->port, status & UART_MSR_CTS);

                        wake_up_interruptible(&up->port.state->port.delta_msr_wait);

            }

 

            return status;

}

 

static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr)

{

            unsigned int flag;

            unsigned char ch = 0;

 

            if (likely(lsr & UART_LSR_DR))

                        ch = serial_in(up, UART_RX);

 

            up->port.icount.rx++;

            flag = TTY_NORMAL;

 

            if (lsr & UART_LSR_BI) {

                        flag = TTY_BREAK;

                        lsr &= ~(UART_LSR_FE | UART_LSR_PE);

                        up->port.icount.brk++;

                        /*

                         * We do the SysRQ and SAK checking

                         * here because otherwise the break

                         * may get masked by ignore_status_mask

                         * or read_status_mask.

                         */

                        if (uart_handle_break(&up->port))

                                    return;

 

            }

 

            if (lsr & UART_LSR_PE) {

                        flag = TTY_PARITY;

                        up->port.icount.parity++;

            }

 

            if (lsr & UART_LSR_FE) {

                        flag = TTY_FRAME;

                        up->port.icount.frame++;

            }

 

            if (lsr & UART_LSR_OE)

                        up->port.icount.overrun++;

 

#ifdef CONFIG_SERIAL_OMAP_CONSOLE

            if (up->port.line == up->port.cons->index) {

                        /* Recover the break flag from console xmit */

                        lsr |= up->lsr_break_flag;

            }

#endif

            uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag);

}

 

static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr)

{

            unsigned char ch = 0;

            unsigned int flag;

 

            if (!(lsr & UART_LSR_DR))

                        return;

 

            ch = serial_in(up, UART_RX);

            flag = TTY_NORMAL;

            up->port.icount.rx++;

 

            if (uart_handle_sysrq_char(&up->port, ch))

                        return;

 

            uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);

}

 

/**

 * serial_omap_irq() - This handles the interrupt from one port

 * @irq: uart port irq number

 * @dev_id: uart port info

 */

static irqreturn_t serial_omap_irq(int irq, void *dev_id)

{

            struct uart_omap_port *up = dev_id;

            struct tty_struct *tty = up->port.state->port.tty;

            unsigned int iir, lsr;

            unsigned int type;

            irqreturn_t ret = IRQ_NONE;

            int max_count = 256;

 

            spin_lock(&up->port.lock);

            pm_runtime_get_sync(up->dev);

 

            do {

                        iir = serial_in(up, UART_IIR);

                        if (iir & UART_IIR_NO_INT)

                                    break;

 

                        ret = IRQ_HANDLED;

                        lsr = serial_in(up, UART_LSR);

 

                        /* extract IRQ type from IIR register */

                        type = iir & 0x3e;

 

                        switch (type) {

                        case UART_IIR_MSI:

                                    check_modem_status(up);

                                    break;

                        case UART_IIR_THRI:

                                    transmit_chars(up, lsr);

                                    break;

                        case UART_IIR_RX_TIMEOUT:

                                    /* FALLTHROUGH */

                        case UART_IIR_RDI:

                                    serial_omap_rdi(up, lsr);

                                    break;

                        case UART_IIR_RLSI:

                                    serial_omap_rlsi(up, lsr);

                                    break;

                        case UART_IIR_CTS_RTS_DSR:

                                    /* simply try again */

                                    break;

                        case UART_IIR_XOFF:

                                    /* FALLTHROUGH */

                        default:

                                    break;

                        }

            } while (!(iir & UART_IIR_NO_INT) && max_count--);

 

            spin_unlock(&up->port.lock);

 

            tty_flip_buffer_push(tty);

 

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

            up->port_activity = jiffies;

 

            return ret;

}

 

static unsigned int serial_omap_tx_empty(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned long flags = 0;

            unsigned int ret = 0;

 

            pm_runtime_get_sync(up->dev);

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

            spin_lock_irqsave(&up->port.lock, flags);

            ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;

            spin_unlock_irqrestore(&up->port.lock, flags);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

            return ret;

}

 

static unsigned int serial_omap_get_mctrl(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned int status;

            unsigned int ret = 0;

 

            pm_runtime_get_sync(up->dev);

            status = check_modem_status(up);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

 

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

 

            if (status & UART_MSR_DCD)

                        ret |= TIOCM_CAR;

            if (status & UART_MSR_RI)

                        ret |= TIOCM_RNG;

            if (status & UART_MSR_DSR)

                        ret |= TIOCM_DSR;

            if (status & UART_MSR_CTS)

                        ret |= TIOCM_CTS;

            return ret;

}

 

static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned char mcr = 0, old_mcr;

 

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

            if (mctrl & TIOCM_RTS)

                        mcr |= UART_MCR_RTS;

            if (mctrl & TIOCM_DTR)

                        mcr |= UART_MCR_DTR;

            if (mctrl & TIOCM_OUT1)

                        mcr |= UART_MCR_OUT1;

            if (mctrl & TIOCM_OUT2)

                        mcr |= UART_MCR_OUT2;

            if (mctrl & TIOCM_LOOP)

                        mcr |= UART_MCR_LOOP;

 

            pm_runtime_get_sync(up->dev);

            old_mcr = serial_in(up, UART_MCR);

            old_mcr &= ~(UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_OUT1 |

                             UART_MCR_DTR | UART_MCR_RTS);

            up->mcr = old_mcr | mcr;

            serial_out(up, UART_MCR, up->mcr);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

 

            if (gpio_is_valid(up->DTR_gpio) &&

                !!(mctrl & TIOCM_DTR) != up->DTR_active) {

                        up->DTR_active = !up->DTR_active;

                        if (gpio_cansleep(up->DTR_gpio))

                                    schedule_work(&up->qos_work);

                        else

                                    gpio_set_value(up->DTR_gpio,

                                                       up->DTR_active != up->DTR_inverted);

            }

}

 

static void serial_omap_break_ctl(struct uart_port *port, int break_state)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned long flags = 0;

 

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

            pm_runtime_get_sync(up->dev);

            spin_lock_irqsave(&up->port.lock, flags);

            if (break_state == -1)

                        up->lcr |= UART_LCR_SBC;

            else

                        up->lcr &= ~UART_LCR_SBC;

            serial_out(up, UART_LCR, up->lcr);

            spin_unlock_irqrestore(&up->port.lock, flags);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

 

static int serial_omap_startup(struct uart_port *port)

{

            struct uart_omap_port *up = to_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->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;

            /*

             * 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->dev);

            pm_runtime_put_autosuspend(up->dev);

            up->port_activity = jiffies;

            return 0;

}

 

static void serial_omap_shutdown(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned long flags = 0;

            int val;

 

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

 

            pm_runtime_get_sync(up->dev);

            /*

             * Disable interrupts from this port

             */

            up->ier = 0;

            serial_out(up, UART_IER, 0);

 

            spin_lock_irqsave(&up->port.lock, flags);

            up->port.mctrl &= ~TIOCM_OUT2;

            serial_omap_set_mctrl(&up->port, up->port.mctrl);

            spin_unlock_irqrestore(&up->port.lock, flags);

 

            /*

             * Disable break condition and FIFOs

             */

            serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);

            serial_omap_clear_fifos(up);

 

            /* if in RS485 mode, make sure we disable the driver */

            if (up->rs485.flags & SER_RS485_ENABLED) {

                        val = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;

                        gpio_set_value(up->rs485.gpio_pin, val);

            }

 

            /*

             * Read data port to reset things, and then free the irq

             */

            if (serial_in(up, UART_LSR) & UART_LSR_DR)

                        (void) serial_in(up, UART_RX);

 

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

            free_irq(up->port.irq, up);

}

 

static void serial_omap_uart_qos_work(struct work_struct *work)

{

            struct uart_omap_port *up = container_of(work, struct uart_omap_port,

                                                                        qos_work);

 

            pm_qos_update_request(&up->pm_qos_request, up->latency);

            if (gpio_is_valid(up->DTR_gpio))

                        gpio_set_value_cansleep(up->DTR_gpio,

                                                            up->DTR_active != up->DTR_inverted);

}

 

static void

serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,

                                    struct ktermios *old)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned char cval = 0;

            unsigned long flags = 0;

            unsigned int baud, quot;

 

            switch (termios->c_cflag & CSIZE) {

            case CS5:

                        cval = UART_LCR_WLEN5;

                        break;

            case CS6:

                        cval = UART_LCR_WLEN6;

                        break;

            case CS7:

                        cval = UART_LCR_WLEN7;

                        break;

            default:

            case CS8:

                        cval = UART_LCR_WLEN8;

                        break;

            }

 

            if (termios->c_cflag & CSTOPB)

                        cval |= UART_LCR_STOP;

            if (termios->c_cflag & PARENB)

                        cval |= UART_LCR_PARITY;

            if (!(termios->c_cflag & PARODD))

                        cval |= UART_LCR_EPAR;

 

            /*

             * Ask the core to calculate the divisor for us.

             */

 

            baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);

            quot = serial_omap_get_divisor(port, baud);

 

            /* calculate wakeup latency constraint */

            up->calc_latency = (USEC_PER_SEC * up->port.fifosize) / (baud / 8);

            up->latency = up->calc_latency;

            schedule_work(&up->qos_work);

 

            up->dll = quot & 0xff;

            up->dlh = quot >> 8;

            up->mdr1 = UART_OMAP_MDR1_DISABLE;

 

            up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |

                                    UART_FCR_ENABLE_FIFO;

 

            /*

             * Ok, we're now changing the port state. Do it with

             * interrupts disabled.

             */

            pm_runtime_get_sync(up->dev);

            spin_lock_irqsave(&up->port.lock, flags);

 

            /*

             * Update the per-port timeout.

             */

            uart_update_timeout(port, termios->c_cflag, baud);

 

            up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;

            if (termios->c_iflag & INPCK)

                        up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;

            if (termios->c_iflag & (BRKINT | PARMRK))

                        up->port.read_status_mask |= UART_LSR_BI;

 

            /*

             * Characters to ignore

             */

            up->port.ignore_status_mask = 0;

            if (termios->c_iflag & IGNPAR)

                        up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;

            if (termios->c_iflag & IGNBRK) {

                        up->port.ignore_status_mask |= UART_LSR_BI;

                        /*

                         * If we're ignoring parity and break indicators,

                         * ignore overruns too (for real raw support).

                         */

                        if (termios->c_iflag & IGNPAR)

                                    up->port.ignore_status_mask |= UART_LSR_OE;

            }

 

            /*

             * ignore all characters if CREAD is not set

             */

            if ((termios->c_cflag & CREAD) == 0)

                        up->port.ignore_status_mask |= UART_LSR_DR;

 

            /*

             * Modem status interrupts

             */

            up->ier &= ~UART_IER_MSI;

            if (UART_ENABLE_MS(&up->port, termios->c_cflag))

                        up->ier |= UART_IER_MSI;

            serial_out(up, UART_IER, up->ier);

            serial_out(up, UART_LCR, cval);             /* reset DLAB */

            up->lcr = cval;

            up->scr = OMAP_UART_SCR_TX_EMPTY;

 

            /* FIFOs and DMA Settings */

 

            /* FCR can be changed only when the

             * baud clock is not running

             * DLL_REG and DLH_REG set to 0.

             */

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);

            serial_out(up, UART_DLL, 0);

            serial_out(up, UART_DLM, 0);

            serial_out(up, UART_LCR, 0);

 

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

 

            up->efr = serial_in(up, UART_EFR) & ~UART_EFR_ECB;

            up->efr &= ~UART_EFR_SCD;

            serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);

 

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);

            up->mcr = serial_in(up, UART_MCR) & ~UART_MCR_TCRTLR;

            serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);

            /* FIFO ENABLE, DMA MODE */

 

            up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;

 

            /* Set receive FIFO threshold to 16 characters and

             * transmit FIFO threshold to 16 spaces

             */

            up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;

            up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK;

            up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 |

                        UART_FCR_ENABLE_FIFO;

 

            serial_out(up, UART_FCR, up->fcr);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

 

            serial_out(up, UART_OMAP_SCR, up->scr);

 

            /* Reset UART_MCR_TCRTLR: this must be done with the EFR_ECB bit set */

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);

            serial_out(up, UART_MCR, up->mcr);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

            serial_out(up, UART_EFR, up->efr);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);

 

            /* Protocol, Baud Rate, and Interrupt Settings */

 

            if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)

                        serial_omap_mdr1_errataset(up, up->mdr1);

            else

                        serial_out(up, UART_OMAP_MDR1, up->mdr1);

 

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

            serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);

 

            serial_out(up, UART_LCR, 0);

            serial_out(up, UART_IER, 0);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

 

            serial_out(up, UART_DLL, up->dll);         /* LS of divisor */

            serial_out(up, UART_DLM, up->dlh);       /* MS of divisor */

 

            serial_out(up, UART_LCR, 0);

            serial_out(up, UART_IER, up->ier);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

 

            serial_out(up, UART_EFR, up->efr);

            serial_out(up, UART_LCR, cval);

 

            if (baud > 230400 && baud != 3000000)

                        up->mdr1 = UART_OMAP_MDR1_13X_MODE;

            else

                        up->mdr1 = UART_OMAP_MDR1_16X_MODE;

 

            if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)

                        serial_omap_mdr1_errataset(up, up->mdr1);

            else

                        serial_out(up, UART_OMAP_MDR1, up->mdr1);

 

            /* Configure flow control */

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

 

            /* XON1/XOFF1 accessible mode B, TCRTLR=0, ECB=0 */

            serial_out(up, UART_XON1, termios->c_cc[VSTART]);

            serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);

 

            /* Enable access to TCR/TLR */

            serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);

            serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);

 

            serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);

 

            if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {

                        /* Enable AUTORTS and AUTOCTS */

                        up->efr |= UART_EFR_CTS | UART_EFR_RTS;

 

                        /* Ensure MCR RTS is asserted */

                        up->mcr |= UART_MCR_RTS;

            } else {

                        /* Disable AUTORTS and AUTOCTS */

                        up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);

            }

 

            if (up->port.flags & UPF_SOFT_FLOW) {

                        /* clear SW control mode bits */

                        up->efr &= OMAP_UART_SW_CLR;

 

                        /*

                         * IXON Flag:

                         * Enable XON/XOFF flow control on input.

                         * Receiver compares XON1, XOFF1.

                         */

                        if (termios->c_iflag & IXON)

                                    up->efr |= OMAP_UART_SW_RX;

 

                        /*

                         * IXOFF Flag:

                         * Enable XON/XOFF flow control on output.

                         * Transmit XON1, XOFF1

                         */

                        if (termios->c_iflag & IXOFF)

                                    up->efr |= OMAP_UART_SW_TX;

 

                        /*

                         * IXANY Flag:

                         * Enable any character to restart output.

                         * Operation resumes after receiving any

                         * character after recognition of the XOFF character

                         */

                        if (termios->c_iflag & IXANY)

                                    up->mcr |= UART_MCR_XONANY;

                        else

                                    up->mcr &= ~UART_MCR_XONANY;

            }

            serial_out(up, UART_MCR, up->mcr);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

            serial_out(up, UART_EFR, up->efr);

            serial_out(up, UART_LCR, up->lcr);

 

            serial_omap_set_mctrl(&up->port, up->port.mctrl);

 

            spin_unlock_irqrestore(&up->port.lock, flags);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

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

}

 

static int serial_omap_set_wake(struct uart_port *port, unsigned int state)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

 

            serial_omap_enable_wakeup(up, state);

 

            return 0;

}

 

static void

serial_omap_pm(struct uart_port *port, unsigned int state,

                   unsigned int oldstate)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned char efr;

 

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

 

            pm_runtime_get_sync(up->dev);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

            efr = serial_in(up, UART_EFR);

            serial_out(up, UART_EFR, efr | UART_EFR_ECB);

            serial_out(up, UART_LCR, 0);

 

            serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

            serial_out(up, UART_EFR, efr);

            serial_out(up, UART_LCR, 0);

 

            if (!device_may_wakeup(up->dev)) {

                        if (!state)

                                    pm_runtime_forbid(up->dev);

                        else

                                    pm_runtime_allow(up->dev);

            }

 

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

 

static void serial_omap_release_port(struct uart_port *port)

{

            dev_dbg(port->dev, "serial_omap_release_port+\n");

}

 

static int serial_omap_request_port(struct uart_port *port)

{

            dev_dbg(port->dev, "serial_omap_request_port+\n");

            return 0;

}

 

static void serial_omap_config_port(struct uart_port *port, int flags)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

 

            dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",

                                                                                    up->port.line);

            up->port.type = PORT_OMAP;

            up->port.flags |= UPF_SOFT_FLOW | UPF_HARD_FLOW;

}

 

static int

serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)

{

            /* we don't want the core code to modify any port params */

            dev_dbg(port->dev, "serial_omap_verify_port+\n");

            return -EINVAL;

}

 

static const char *

serial_omap_type(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

 

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

            return up->name;

}

 

#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)

 

static inline void wait_for_xmitr(struct uart_omap_port *up)

{

            unsigned int status, tmout = 10000;

 

            /* Wait up to 10ms for the character(s) to be sent. */

            do {

                        status = serial_in(up, UART_LSR);

 

                        if (status & UART_LSR_BI)

                                    up->lsr_break_flag = UART_LSR_BI;

 

                        if (--tmout == 0)

                                    break;

                        udelay(1);

            } while ((status & BOTH_EMPTY) != BOTH_EMPTY);

 

            /* Wait up to 1s for flow control if necessary */

            if (up->port.flags & UPF_CONS_FLOW) {

                        tmout = 1000000;

                        for (tmout = 1000000; tmout; tmout--) {

                                    unsigned int msr = serial_in(up, UART_MSR);

 

                                    up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;

                                    if (msr & UART_MSR_CTS)

                                                break;

 

                                    udelay(1);

                        }

            }

}

 

#ifdef CONFIG_CONSOLE_POLL

 

static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

 

            pm_runtime_get_sync(up->dev);

            wait_for_xmitr(up);

            serial_out(up, UART_TX, ch);

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

}

 

static int serial_omap_poll_get_char(struct uart_port *port)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

            unsigned int status;

 

            pm_runtime_get_sync(up->dev);

            status = serial_in(up, UART_LSR);

            if (!(status & UART_LSR_DR)) {

                        status = NO_POLL_CHAR;

                        goto out;

            }

 

            status = serial_in(up, UART_RX);

 

out:

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

 

            return status;

}

 

#endif /* CONFIG_CONSOLE_POLL */

 

#ifdef CONFIG_SERIAL_OMAP_CONSOLE

 

static struct uart_omap_port *serial_omap_console_ports[OMAP_MAX_HSUART_PORTS];

 

static struct uart_driver serial_omap_reg;

 

static void serial_omap_console_putchar(struct uart_port *port, int ch)

{

            struct uart_omap_port *up = to_uart_omap_port(port);

 

            wait_for_xmitr(up);

            serial_out(up, UART_TX, ch);

}

 

static void

serial_omap_console_write(struct console *co, const char *s,

                        unsigned int count)

{

            struct uart_omap_port *up = serial_omap_console_ports[co->index];

            unsigned long flags;

            unsigned int ier;

            int locked = 1;

 

            pm_runtime_get_sync(up->dev);

 

            local_irq_save(flags);

            if (up->port.sysrq)

                        locked = 0;

            else if (oops_in_progress)

                        locked = spin_trylock(&up->port.lock);

            else

                        spin_lock(&up->port.lock);

 

            /*

             * First save the IER then disable the interrupts

             */

            ier = serial_in(up, UART_IER);

            serial_out(up, UART_IER, 0);

 

            uart_console_write(&up->port, s, count, serial_omap_console_putchar);

 

            /*

             * Finally, wait for transmitter to become empty

             * and restore the IER

             */

            wait_for_xmitr(up);

            serial_out(up, UART_IER, ier);

            /*

             * The receive handling will happen properly because the

             * receive ready bit will still be set; it is not cleared

             * on read.  However, modem control will not, we must

             * call it if we have saved something in the saved flags

             * while processing with interrupts off.

             */

            if (up->msr_saved_flags)

                        check_modem_status(up);

 

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

            if (locked)

                        spin_unlock(&up->port.lock);

            local_irq_restore(flags);

}

 

static int __init

serial_omap_console_setup(struct console *co, char *options)

{

            struct uart_omap_port *up;

            int baud = 115200;

            int bits = 8;

            int parity = 'n';

            int flow = 'n';

 

            if (serial_omap_console_ports[co->index] == NULL)

                        return -ENODEV;

            up = serial_omap_console_ports[co->index];

 

            if (options)

                        uart_parse_options(options, &baud, &parity, &bits, &flow);

 

            return uart_set_options(&up->port, co, baud, parity, bits, flow);

}

 

static struct console serial_omap_console = {

            .name               = OMAP_SERIAL_NAME,

            .write                = serial_omap_console_write,

            .device             = uart_console_device,

            .setup               = serial_omap_console_setup,

            .flags                = CON_PRINTBUFFER,

            .index               = -1,

            .data                 = &serial_omap_reg,

};

 

static void serial_omap_add_console_port(struct uart_omap_port *up)

{

            serial_omap_console_ports[up->port.line] = up;

}

 

#define OMAP_CONSOLE         (&serial_omap_console)

 

#else

 

#define OMAP_CONSOLE         NULL

 

static inline void serial_omap_add_console_port(struct uart_omap_port *up)

{}

 

#endif

 

 

static int

serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)

{

            int r = 0;

            int val;

            struct uart_omap_port *p = (struct uart_omap_port *)port;

 

            spin_lock(&port->lock);

 

            /* TODO - disable transmitter ? */

 

            if (rs485conf->flags & SER_RS485_ENABLED) {

                        val = (p->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;

                        /* if using GPIO, request the resource and set it up */

 

                        if (rs485conf->flags & SER_RS485_USE_GPIO) {

                                    /* get gpio resources if not already set */

                                    if (!(p->rs485.flags & SER_RS485_USE_GPIO) ||

                                         (p->rs485.gpio_pin != rs485conf->gpio_pin)) {

 

                                                r = gpio_request(rs485conf->gpio_pin,

                                                                 "RS485 TXE");

                                                if (r) {

                                                            dev_warn(port->dev,

                                                                    "Could not request GPIO %d : %d\n",

                                                                    rs485conf->gpio_pin, r);

                                                            r = -EFAULT;

                                                            goto exit_bail;

                                                }

 

                                                r = gpio_direction_output(rs485conf->gpio_pin, val);

                                                if (r) {

                                                            dev_warn(port->dev,

                                                                   "Could not drive GPIO %d : %d\n",

                                                                           rs485conf->gpio_pin, r);

                                                            r = -EFAULT;

                                                            goto exit_bail;

                                                }

 

                                                /* free up old pin */

                                                //TODO: What if old pin is same as current?!!?!?

                                                //if (p->rs485.flags & SER_RS485_USE_GPIO)

                                                            //gpio_free(p->rs485.gpio_pin);

                                    }

                        } else { /* RTS pin requested */

                                    dev_warn(port->dev, "Must use GPIO for RS485 Support\n");

                                    goto exit_bail;

                        }

            }

            p->rs485 = *rs485conf;

 

exit_bail:

            spin_unlock(&port->lock);

            return r;

}

 

static int

serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)

{

            struct serial_rs485 rs485conf;

            switch (cmd) {

            case TIOCSRS485:

                        printk("rs485 v1.1\n");

                        if (copy_from_user(&rs485conf, (struct serial_rs485 *)arg,

                                            sizeof(rs485conf)))

                                    return -EFAULT;

                        serial_omap_config_rs485(port, &rs485conf);

                        break;

 

            case TIOCGRS485:

                        printk("rs485 v1.1\n");

                        if (copy_to_user((struct serial_rs485 *)arg,

                                       &((struct uart_omap_port *)port)->rs485,

                                       sizeof(rs485conf)))

                                    return -EFAULT;

                        break;

 

            default:

                        return -ENOIOCTLCMD;

            }

 

            return 0;

}

 

 

static struct uart_ops serial_omap_pops = {

            .tx_empty         = serial_omap_tx_empty,

            .set_mctrl          = serial_omap_set_mctrl,

            .get_mctrl         = serial_omap_get_mctrl,

            .stop_tx            = serial_omap_stop_tx,

            .start_tx            = serial_omap_start_tx,

            .throttle = serial_omap_throttle,

            .unthrottle         = serial_omap_unthrottle,

            .stop_rx            = serial_omap_stop_rx,

            .enable_ms       = serial_omap_enable_ms,

            .break_ctl          = serial_omap_break_ctl,

            .startup = serial_omap_startup,

            .shutdown         = serial_omap_shutdown,

            .set_termios      = serial_omap_set_termios,

            .pm                  = serial_omap_pm,

            .set_wake         = serial_omap_set_wake,

            .type                 = serial_omap_type,

            .release_port     = serial_omap_release_port,

            .request_port    = serial_omap_request_port,

            .config_port      = serial_omap_config_port,

            .verify_port       = serial_omap_verify_port,

            .ioctl                 = serial_omap_ioctl,

#ifdef CONFIG_CONSOLE_POLL

            .poll_put_char  = serial_omap_poll_put_char,

            .poll_get_char  = serial_omap_poll_get_char,

#endif

};

 

static struct uart_driver serial_omap_reg = {

            .owner              = THIS_MODULE,

            .driver_name     = "OMAP-SERIAL",

            .dev_name        = OMAP_SERIAL_NAME,

            .nr                    = OMAP_MAX_HSUART_PORTS,

            .cons                = OMAP_CONSOLE,

};

 

#ifdef CONFIG_PM_SLEEP

static int serial_omap_suspend(struct device *dev)

{

            struct uart_omap_port *up = dev_get_drvdata(dev);

 

            uart_suspend_port(&serial_omap_reg, &up->port);

            flush_work(&up->qos_work);

 

            return 0;

}

 

static int serial_omap_resume(struct device *dev)

{

            struct uart_omap_port *up = dev_get_drvdata(dev);

 

            uart_resume_port(&serial_omap_reg, &up->port);

 

            return 0;

}

#endif

 

static void omap_serial_fill_features_erratas(struct uart_omap_port *up)

{

            u32 mvr, scheme;

            u16 revision, major, minor;

 

            mvr = serial_in(up, UART_OMAP_MVER);

 

            /* Check revision register scheme */

            scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;

 

            switch (scheme) {

            case 0: /* Legacy Scheme: OMAP2/3 */

                        /* MINOR_REV[0:4], MAJOR_REV[4:7] */

                        major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>

                                                            OMAP_UART_LEGACY_MVR_MAJ_SHIFT;

                        minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);

                        break;

            case 1:

                        /* New Scheme: OMAP4+ */

                        /* MINOR_REV[0:5], MAJOR_REV[8:10] */

                        major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>

                                                            OMAP_UART_MVR_MAJ_SHIFT;

                        minor = (mvr & OMAP_UART_MVR_MIN_MASK);

                        break;

            default:

                        dev_warn(up->dev,

                                    "Unknown %s revision, defaulting to highest\n",

                                    up->name);

                        /* highest possible revision */

                        major = 0xff;

                        minor = 0xff;

            }

 

            /* normalize revision for the driver */

            revision = UART_BUILD_REVISION(major, minor);

 

            switch (revision) {

            case OMAP_UART_REV_46:

                        up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |

                                                UART_ERRATA_i291_DMA_FORCEIDLE);

                        break;

            case OMAP_UART_REV_52:

                        up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |

                                                UART_ERRATA_i291_DMA_FORCEIDLE);

                        break;

            case OMAP_UART_REV_63:

                        up->errata |= UART_ERRATA_i202_MDR1_ACCESS;

                        break;

            default:

                        break;

            }

}

 

static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)

{

            struct omap_uart_port_info *omap_up_info;

 

            omap_up_info = devm_kzalloc(dev, sizeof(*omap_up_info), GFP_KERNEL);

            if (!omap_up_info)

                        return NULL; /* out of memory */

 

            of_property_read_u32(dev->of_node, "clock-frequency",

                                                             &omap_up_info->uartclk);

            return omap_up_info;

}

 

static int serial_omap_probe(struct platform_device *pdev)

{

            struct uart_omap_port   *up;

            struct resource              *mem, *irq;

            struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;

            int ret;

 

            if (pdev->dev.of_node)

                        omap_up_info = of_get_uart_port_info(&pdev->dev);

 

            mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

            if (!mem) {

                        dev_err(&pdev->dev, "no mem resource?\n");

                        return -ENODEV;

            }

 

            irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

            if (!irq) {

                        dev_err(&pdev->dev, "no irq resource?\n");

                        return -ENODEV;

            }

 

            if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),

                                                pdev->dev.driver->name)) {

                        dev_err(&pdev->dev, "memory region already claimed\n");

                        return -EBUSY;

            }

 

            if (gpio_is_valid(omap_up_info->DTR_gpio) &&

                omap_up_info->DTR_present) {

                        ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");

                        if (ret < 0)

                                    return ret;

                        ret = gpio_direction_output(omap_up_info->DTR_gpio,

                                                                omap_up_info->DTR_inverted);

                        if (ret < 0)

                                    return ret;

            }

 

            up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);

            if (!up)

                        return -ENOMEM;

 

            if (gpio_is_valid(omap_up_info->DTR_gpio) &&

                omap_up_info->DTR_present) {

                        up->DTR_gpio = omap_up_info->DTR_gpio;

                        up->DTR_inverted = omap_up_info->DTR_inverted;

            } else

                        up->DTR_gpio = -EINVAL;

            up->DTR_active = 0;

 

            up->dev = &pdev->dev;

            up->port.dev = &pdev->dev;

            up->port.type = PORT_OMAP;

            up->port.iotype = UPIO_MEM;

            up->port.irq = irq->start;

 

            up->port.regshift = 2;

            up->port.fifosize = 64;

            up->port.ops = &serial_omap_pops;

 

            if (pdev->dev.of_node)

                        up->port.line = of_alias_get_id(pdev->dev.of_node, "serial");

            else

                        up->port.line = pdev->id;

 

            if (up->port.line < 0) {

                        dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n",

                                                                                                up->port.line);

                        ret = -ENODEV;

                        goto err_port_line;

            }

 

            up->pins = devm_pinctrl_get_select_default(&pdev->dev);

            if (IS_ERR(up->pins)) {

                        dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n",

                                     up->port.line, PTR_ERR(up->pins));

                        up->pins = NULL;

            }

 

            sprintf(up->name, "OMAP UART%d", up->port.line);

            up->port.mapbase = mem->start;

            up->port.membase = devm_ioremap(&pdev->dev, mem->start,

                                                                        resource_size(mem));

            if (!up->port.membase) {

                        dev_err(&pdev->dev, "can't ioremap UART\n");

                        ret = -ENOMEM;

                        goto err_ioremap;

            }

 

            up->port.flags = omap_up_info->flags;

            up->port.uartclk = omap_up_info->uartclk;

            if (!up->port.uartclk) {

                        up->port.uartclk = DEFAULT_CLK_SPEED;

                        dev_warn(&pdev->dev, "No clock speed specified: using default:"

                                                                        "%d\n", DEFAULT_CLK_SPEED);

            }

 

            up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;

            up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;

            pm_qos_add_request(&up->pm_qos_request,

                        PM_QOS_CPU_DMA_LATENCY, up->latency);

            serial_omap_uart_wq = create_singlethread_workqueue(up->name);

            INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);

 

            platform_set_drvdata(pdev, up);

            pm_runtime_enable(&pdev->dev);

            pm_runtime_use_autosuspend(&pdev->dev);

            pm_runtime_set_autosuspend_delay(&pdev->dev,

                                    omap_up_info->autosuspend_timeout);

 

            pm_runtime_irq_safe(&pdev->dev);

            pm_runtime_get_sync(&pdev->dev);

 

            omap_serial_fill_features_erratas(up);

 

            ui[up->port.line] = up;

            serial_omap_add_console_port(up);

 

            ret = uart_add_one_port(&serial_omap_reg, &up->port);

            if (ret != 0)

                        goto err_add_port;

 

            pm_runtime_mark_last_busy(up->dev);

            pm_runtime_put_autosuspend(up->dev);

            return 0;

 

err_add_port:

            pm_runtime_put(&pdev->dev);

            pm_runtime_disable(&pdev->dev);

err_ioremap:

err_port_line:

            dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",

                                                pdev->id, __func__, ret);

            return ret;

}

 

static int serial_omap_remove(struct platform_device *dev)

{

            struct uart_omap_port *up = platform_get_drvdata(dev);

 

            pm_runtime_put_sync(up->dev);

            pm_runtime_disable(up->dev);

            uart_remove_one_port(&serial_omap_reg, &up->port);

            pm_qos_remove_request(&up->pm_qos_request);

 

            return 0;

}

 

/*

 * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)

 * The access to uart register after MDR1 Access

 * causes UART to corrupt data.

 *

 * Need a delay =

 * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)

 * give 10 times as much

 */

static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1)

{

            u8 timeout = 255;

 

            serial_out(up, UART_OMAP_MDR1, mdr1);

            udelay(2);

            serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT |

                                    UART_FCR_CLEAR_RCVR);

            /*

             * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and

             * TX_FIFO_E bit is 1.

             */

            while (UART_LSR_THRE != (serial_in(up, UART_LSR) &

                                                (UART_LSR_THRE | UART_LSR_DR))) {

                        timeout--;

                        if (!timeout) {

                                    /* Should *never* happen. we warn and carry on */

                                    dev_crit(up->dev, "Errata i202: timedout %x\n",

                                                                        serial_in(up, UART_LSR));

                                    break;

                        }

                        udelay(1);

            }

}

 

#ifdef CONFIG_PM_RUNTIME

static void serial_omap_restore_context(struct uart_omap_port *up)

{

            if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)

                        serial_omap_mdr1_errataset(up, UART_OMAP_MDR1_DISABLE);

            else

                        serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);

 

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */

            serial_out(up, UART_EFR, UART_EFR_ECB);

            serial_out(up, UART_LCR, 0x0); /* Operational mode */

            serial_out(up, UART_IER, 0x0);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */

            serial_out(up, UART_DLL, up->dll);

            serial_out(up, UART_DLM, up->dlh);

            serial_out(up, UART_LCR, 0x0); /* Operational mode */

            serial_out(up, UART_IER, up->ier);

            serial_out(up, UART_FCR, up->fcr);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);

            serial_out(up, UART_MCR, up->mcr);

            serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */

            serial_out(up, UART_OMAP_SCR, up->scr);

            serial_out(up, UART_EFR, up->efr);

            serial_out(up, UART_LCR, up->lcr);

            if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)

                        serial_omap_mdr1_errataset(up, up->mdr1);

            else

                        serial_out(up, UART_OMAP_MDR1, up->mdr1);

}

 

static int serial_omap_runtime_suspend(struct device *dev)

{

            struct uart_omap_port *up = dev_get_drvdata(dev);

            struct omap_uart_port_info *pdata = dev->platform_data;

 

            if (!up)

                        return -EINVAL;

 

            if (!pdata)

                        return 0;

 

            up->context_loss_cnt = serial_omap_get_context_loss_count(up);

 

            if (device_may_wakeup(dev)) {

                        if (!up->wakeups_enabled) {

                                    serial_omap_enable_wakeup(up, true);

                                    up->wakeups_enabled = true;

                        }

            } else {

                        if (up->wakeups_enabled) {

                                    serial_omap_enable_wakeup(up, false);

                                    up->wakeups_enabled = false;

                        }

            }

 

            up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;

            schedule_work(&up->qos_work);

 

            return 0;

}

 

static int serial_omap_runtime_resume(struct device *dev)

{

            struct uart_omap_port *up = dev_get_drvdata(dev);

 

            int loss_cnt = serial_omap_get_context_loss_count(up);

 

            if (loss_cnt < 0) {

                        dev_err(dev, "serial_omap_get_context_loss_count failed : %d\n",

                                    loss_cnt);

                        serial_omap_restore_context(up);

            } else if (up->context_loss_cnt != loss_cnt) {

                        serial_omap_restore_context(up);

            }

            up->latency = up->calc_latency;

            schedule_work(&up->qos_work);

 

            return 0;

}

#endif

 

static const struct dev_pm_ops serial_omap_dev_pm_ops = {

            SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume)

            SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend,

                                                serial_omap_runtime_resume, NULL)

};

 

#if defined(CONFIG_OF)

static const struct of_device_id omap_serial_of_match[] = {

            { .compatible = "ti,omap2-uart" },

            { .compatible = "ti,omap3-uart" },

            { .compatible = "ti,omap4-uart" },

            {},

};

MODULE_DEVICE_TABLE(of, omap_serial_of_match);

#endif

 

static struct platform_driver serial_omap_driver = {

            .probe          = serial_omap_probe,

            .remove         = serial_omap_remove,

            .driver               = {

                        .name   = DRIVER_NAME,

                        .pm      = &serial_omap_dev_pm_ops,

                        .of_match_table = of_match_ptr(omap_serial_of_match),

            },

};

 

static int __init serial_omap_init(void)

{

            int ret;

 

            ret = uart_register_driver(&serial_omap_reg);

            if (ret != 0)

                        return ret;

            ret = platform_driver_register(&serial_omap_driver);

            if (ret != 0)

                        uart_unregister_driver(&serial_omap_reg);

            return ret;

}

 

static void __exit serial_omap_exit(void)

{

            platform_driver_unregister(&serial_omap_driver);

            uart_unregister_driver(&serial_omap_reg);

}

 

module_init(serial_omap_init);

module_exit(serial_omap_exit);

 

MODULE_DESCRIPTION("OMAP High Speed UART driver");

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Texas Instruments Inc");

 

serial.h

/*

 * include/linux/serial.h

 *

 * Copyright (C) 1992 by Theodore Ts'o.

 * 

 * Redistribution of this file is permitted under the terms of the GNU 

 * Public License (GPL)

 */

 

#ifndef _UAPI_LINUX_SERIAL_H

#define _UAPI_LINUX_SERIAL_H

 

#include <linux/types.h>

 

#include <linux/tty_flags.h>

 

 

struct serial_struct {

            int         type;

            int         line;

            unsigned int      port;

            int         irq;

            int         flags;

            int         xmit_fifo_size;

            int         custom_divisor;

            int         baud_base;

            unsigned short  close_delay;

            char      io_type;

            char      reserved_char[1];

            int         hub6;

            unsigned short  closing_wait; /* time to wait before closing */

            unsigned short  closing_wait2; /* no longer used... */

            unsigned char   *iomem_base;

            unsigned short  iomem_reg_shift;

            unsigned int      port_high;

            unsigned long   iomap_base;     /* cookie passed into ioremap */

};

 

/*

 * For the close wait times, 0 means wait forever for serial port to

 * flush its output.  65535 means don't wait at all.

 */

#define ASYNC_CLOSING_WAIT_INF     0

#define ASYNC_CLOSING_WAIT_NONE            65535

 

/*

 * These are the supported serial types.

 */

#define PORT_UNKNOWN         0

#define PORT_8250       1

#define PORT_16450     2

#define PORT_16550     3

#define PORT_16550A   4

#define PORT_CIRRUS     5       /* usurped by cyclades.c */

#define PORT_16650     6

#define PORT_16650V2 7

#define PORT_16750     8

#define PORT_STARTECH         9          /* usurped by cyclades.c */

#define PORT_16C950   10         /* Oxford Semiconductor */

#define PORT_16654     11

#define PORT_16850     12

#define PORT_RSA       13         /* RSA-DV II/S card */

#define PORT_MAX      13

 

#define SERIAL_IO_PORT         0

#define SERIAL_IO_HUB6         1

#define SERIAL_IO_MEM          2

 

#define UART_CLEAR_FIFO                  0x01

#define UART_USE_FIFO                      0x02

#define UART_STARTECH                     0x04

#define UART_NATSEMI                        0x08

 

 

/*

 * Multiport serial configuration structure --- external structure

 */

struct serial_multiport_struct {

            int                     irq;

            int                     port1;

            unsigned char   mask1, match1;

            int                     port2;

            unsigned char   mask2, match2;

            int                     port3;

            unsigned char   mask3, match3;

            int                     port4;

            unsigned char   mask4, match4;

            int                     port_monitor;

            int         reserved[32];

};

 

/*

 * Serial input interrupt line counters -- external structure

 * Four lines can interrupt: CTS, DSR, RI, DCD

 */

struct serial_icounter_struct {

            int cts, dsr, rng, dcd;

            int rx, tx;

            int frame, overrun, parity, brk;

            int buf_overrun;

            int reserved[9];

};

 

/*

 * Serial interface for controlling RS485 settings on chips with suitable

 * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your

 * platform. The set function returns the new state, with any unsupported bits

 * reverted appropriately.

 */

 

struct serial_rs485 {

        __u32   flags;                                /* RS485 feature flags */

            #define SER_RS485_ENABLED               (1 << 0)

            #define SER_RS485_RTS_ON_SEND           (1 << 1)

            #define SER_RS485_RTS_AFTER_SEND        (1 << 2)

            #define SER_RS485_RTS_BEFORE_SEND       (1 << 3)

            #define SER_RS485_USE_GPIO              (1 << 5)

        __u32   delay_rts_before_send;                 /* Microseconds */

        __u32   delay_rts_after_send;                    /* Microseconds */

        __u32   gpio_pin;                                      /* GPIO Pin Index */

        __u32   padding[4];                                   /* Memory is cheap, new structs are a royal PITA .. */

};

 

#endif /* _UAPI_LINUX_SERIAL_H */

Robert Nelson

unread,
May 28, 2014, 11:32:39 AM5/28/14
to Beagle Board
On Wed, May 28, 2014 at 2:38 AM, <lexdup...@gmail.com> wrote:
> Sorry for taking so long to come back but was a bit busy. It looks like the
> RS 485 patch is not included in the standard Debian release for the
> Beaglebone Black (with all the other patches that is included). So if you
> are using Debian on the Beaglebone Black you have to apply the RS 485 patch
> of Mickae1 manually before compiling else you could replace
> /kernel/drivers/tty/serial/omap-serial.c with the code at the end and also
> replace /kernel/uapi/linux/serial.h with the code at the end and recompile.
> Then just pass the structure as discussed above. Make these changes before
> applying the additional patches for the Debian image.

So what exactly are we missing for RS 485 support?

https://github.com/RobertCNelson/bb-kernel/blob/am33x-v3.8/patch.sh#L866

https://github.com/RobertCNelson/bb-kernel/blob/am33x-v3.8/patches/fixes/0007-omap-RS485-support-by-Michael-Musset.patch

Regards,

--
Robert Nelson
http://www.rcn-ee.com/

Micka

unread,
May 28, 2014, 11:45:23 AM5/28/14
to beagl...@googlegroups.com
Robert .... It works perfectly your Debian Image with the RS485  .... I don't understand what is the problem .... .




Regards,


lexdup...@gmail.com

unread,
May 29, 2014, 12:49:42 AM5/29/14
to beagl...@googlegroups.com

Hi Robert

I agree with Mickae1 because I have several Debian Images that work perfectly but some of the the RS485 structure in serial.h never gets changed will applying patch.sh. It says that 0007-omap-RS485-support-by-Michael-Musset.patch is applied but later when I pass the structure in code it gives an error in regards to the the directional pin that is not defined or something another which leads me back to serial.h which is missing the patched RS 485 structure. Just found in those cases to manually edit omap-serial.c and serial.h which resolves this problem.

Love your work and do learn something new every day.

Regards

slro...@gmail.com

unread,
Jan 19, 2016, 2:07:57 PM1/19/16
to BeagleBoard, lexdup...@gmail.com
Hi, 
 Im having the same issue getting the RS-485 working on the latest debian 4.2.4 bone2 Beagle Bone Black build. Is there a header file to include with this source code? and is this source code  complete?
Thanks
Reply all
Reply to author
Forward
0 new messages