Ok,

Well, the baudrate is at 38400, the distribution is the Ubuntu from Robert
C Nelson ( 3.8.13 bone 30 ), the driver is the omap . I've modified a
little bit the driver to add RS485 support ( see the patch attached ) , the
only major modification that I've done is to add :

+ 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);
+        }


in the function serial_omap_stop_tx .


It works most of the time, but for an unknown reason there is this weird
behavior .....


Any tips ? lead to follow ?


On Fri, Jan 3, 2014 at 11:38 PM, William Hermans <[email protected]> wrote:

> You're missing a bunch of information needed to help troubleshoot/ For
> starters how fast ? Which distro ? Which kernel driver are you using ? etc
> etc etc.
>
>
> On Fri, Jan 3, 2014 at 8:55 AM, Micka <[email protected]> wrote:
>
>> Hi,
>>
>> I would like to know if someone has experienced data sliced in two pieces
>> ?
>>
>> My case is simple, the UART in the beagleBone Black send the data in two
>> piece .....
>>
>> The problem is that the device answer with an error crc ....
>>
>> so why the uart is doing that ?
>>
>>
>> Micka,
>>
>> --
>> 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 [email protected].
>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>
>  --
> 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 [email protected].
> For more options, visit https://groups.google.com/groups/opt_out.
>

-- 
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 [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 57d6b29..aa71c13 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -37,6 +37,8 @@
 #include <linux/clk.h>
 #include <linux/serial_core.h>
 #include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/gpio.h>
@@ -160,6 +162,7 @@ struct uart_omap_port {
        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)))
@@ -268,11 +271,11 @@ static void serial_omap_enable_ms(struct uart_port *port)
        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;
@@ -283,6 +286,15 @@ static void serial_omap_stop_tx(struct uart_port *port)
 
        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)
@@ -345,12 +357,23 @@ static inline void serial_omap_enable_ier_thri(struct 
uart_omap_port *up)
 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)
@@ -702,6 +725,7 @@ 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);
 
@@ -722,6 +746,12 @@ static void serial_omap_shutdown(struct uart_port *port)
         */
        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
@@ -1250,6 +1280,93 @@ 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\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\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,
@@ -1271,6 +1388,7 @@ static struct uart_ops serial_omap_pops = {
        .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,
diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 5e0d0ed..1830ceb 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -109,18 +109,16 @@ struct serial_icounter_struct {
  */
 
 struct serial_rs485 {
-       __u32   flags;                  /* RS485 feature flags */
-#define SER_RS485_ENABLED              (1 << 0)        /* If enabled */
-#define SER_RS485_RTS_ON_SEND          (1 << 1)        /* Logical level for
-                                                          RTS pin when
-                                                          sending */
-#define SER_RS485_RTS_AFTER_SEND       (1 << 2)        /* Logical level for
-                                                          RTS pin after sent*/
-#define SER_RS485_RX_DURING_TX         (1 << 4)
-       __u32   delay_rts_before_send;  /* Delay before send (milliseconds) */
-       __u32   delay_rts_after_send;   /* Delay after send (milliseconds) */
-       __u32   padding[5];             /* Memory is cheap, new structs
-                                          are a royal PITA .. */
-};
-
+          __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 */

Reply via email to