Here my rewritten patch for rs485 support for kernel 2.6.24.7

Read/write direction ot differential bus transceiver will be changed by /RTS 
with output port register 0p0 and 0p1;
To switch uart to rs485 mode, a 1 has to be written to 
/sys/dev/f00000000.soc5200/f0002x000.serial/uartmode. 
*void private_data in struct uart_port will point t a variable for each port to 
mark
mode.
A uart console can not be switched to rs485 mode

Maybe this is usefull for somebody

Criticism is welcome

cheers


diff -uprN linux-2.6.24.7-el392-rt11-can751_org/drivers/serial/Kconfig 
linux-2.6.24.7-el392-rt11-can751/drivers/serial/Kconfig
--- linux-2.6.24.7-el392-rt11-can751_org/drivers/serial/Kconfig 2008-10-16 
13:35:31.000000000 +0200
+++ linux-2.6.24.7-el392-rt11-can751/drivers/serial/Kconfig     2008-11-13 
15:44:19.000000000 +0100
@@ -1123,6 +1123,13 @@ config SERIAL_MPC52xx
          for use as console, it must be included in kernel and not as a
          module.
 
+config SERIAL_RS485
+       bool "RS485 support"
+       depends on SERIAL_MPC52xx
+       help
+         This drivers support serial RS485 ports. If you like 
+         to use them, answer Y to this option.
+
 config SERIAL_MPC52xx_CONSOLE
        bool "Console on a Freescale MPC52xx family PSC serial port"
        depends on SERIAL_MPC52xx=y
diff -uprN linux-2.6.24.7-el392-rt11-can751_org/drivers/serial/mpc52xx_uart.c 
linux-2.6.24.7-el392-rt11-can751/drivers/serial/mpc52xx_uart.c
--- linux-2.6.24.7-el392-rt11-can751_org/drivers/serial/mpc52xx_uart.c  
2008-10-16 13:40:15.000000000 +0200
+++ linux-2.6.24.7-el392-rt11-can751/drivers/serial/mpc52xx_uart.c      
2008-11-17 15:55:07.000000000 +0100
@@ -21,11 +21,25 @@
  * Copyright (C) 2004-2006 Sylvain Munaut <[EMAIL PROTECTED]>
  * Copyright (C) 2003 MontaVista, Software, Inc.
  *
+ * RS485 support is written by Hans Lehmann 
+ *     <[EMAIL PROTECTED]>
+ *
  * This file is licensed under the terms of the GNU General Public License
  * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
  */
 
+/* RS485 Usage:
+ * The driver will autmaticly handle a uart port in RS485 mode if you set 
uartmode
+ * in /sys/device/f00000000.soc5200/f0002x000.serial to 1
+ * "echo 1 >  /sys/device/f00000000.soc5200/f0002x000.serial/uartmode
+ * We misuse void pointer private->data in struct uart_port
+ * to determinate handle of port.
+ * RTS bit is used to set direction of differential bus transceiver
+ * Set mpc52xx_psc_op1 asserts output port /RTS: Write
+ * Set mpc52xx_psc_op0 negate output port /RTS: Read
+*/
+
 /* Platform device Usage :
  *
  * Since PSCs can have multiple function, the correct driver for each one
@@ -94,6 +108,12 @@
 
 #define ISR_PASS_LIMIT 256     /* Max number of iteration in the interrupt */
 
+#define        RS485_SET_RTS           0x01            /* for ouput port 1 bit 
set */
+#define        RS485_CLR_RTS           RS485_SET_RTS   /* for ouput port 0 bit 
set */
+
+#define RS485                  1
+#define RS232                  0
+
 
 static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
        /* Rem: - We use the read_status_mask as a shadow of
@@ -132,6 +152,12 @@ static struct of_device_id mpc52xx_uart_
 };
 #endif
 
+/* Simple variable to set private->data
+ * private data will be used to test, how to handle port
+*/ 
+#ifdef CONFIG_SERIAL_RS485
+int uartmode = RS232;
+#endif /* CONFIG_SERIAL_RS485 */
 
 /* ======================================================================== */
 /* UART operations                                                          */
@@ -144,6 +170,20 @@ mpc52xx_uart_tx_empty(struct uart_port *
        return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
 }
 
+#ifdef CONFIG_SERIAL_RS485
+static void
+mpc52xx_uart_rs485_rts_clear(struct uart_port *port)
+{
+       /* In RS485 mode negate output port /RTS after 
+        * TX empty (underrun) IRQ, to be able to receive data, directly
+       */ 
+       out_8(&PSC(port)->mpc52xx_psc_op0, RS485_SET_RTS);      
+       port->read_status_mask &= ~MPC52xx_PSC_IMR_TXEMP 
+                              & ~MPC52xx_PSC_IMR_TXRDY;
+       out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+}
+#endif /* CONFIG_SERIAL_RS485 */
+
 static void
 mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
@@ -168,8 +208,18 @@ mpc52xx_uart_stop_tx(struct uart_port *p
 static void
 mpc52xx_uart_start_tx(struct uart_port *port)
 {
-       /* port->lock taken by caller */
-       port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+       /* port->lock taken by caller */        
+#ifdef CONFIG_SERIAL_RS485
+       if (*(int *)port->private_data){
+               /* Set /RTS immidiate before start transaction 
+                * Make sure tx empty interrupt is on 
+               */
+               port->read_status_mask |= MPC52xx_PSC_IMR_TXEMP 
+                                      | MPC52xx_PSC_IMR_TXRDY;
+               out_8(&PSC(port)->mpc52xx_psc_op1, RS485_CLR_RTS);
+       } else
+#endif /* CONFIG_SERIAL_RS485 */
+               port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
        out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
 }
 
@@ -513,6 +563,14 @@ mpc52xx_uart_int_tx_chars(struct uart_po
 {
        struct circ_buf *xmit = &port->info->xmit;
 
+#ifdef CONFIG_SERIAL_RS485
+       /* Tx Empty in RS485 Mode */
+       if (uart_circ_empty(xmit) && mpc52xx_uart_tx_empty(port)){
+               mpc52xx_uart_rs485_rts_clear(port);     
+               return 0;       
+       }
+#endif /* CONFIG_SERIAL_RS485 */
+       
        /* Process out of band chars */
        if (port->x_char) {
                out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char);
@@ -578,6 +636,15 @@ mpc52xx_uart_int(int irq, void *dev_id)
                if ( status & MPC52xx_PSC_IMR_TXRDY )
                        keepgoing |= mpc52xx_uart_int_tx_chars(port);
 
+#ifdef CONFIG_SERIAL_RS485
+               /* Do we need to send chars in RS485 mode ? */
+               /* For this, TX must be ready, TX and TX empty 
+                * interrupt enabled 
+               */
+               if ((*(int *)port->private_data) && (status & 
MPC52xx_PSC_IMR_TXEMP))
+                       keepgoing |= mpc52xx_uart_int_tx_chars(port);
+#endif /* CONFIG_SERIAL_RS485 */
+
                /* Limit number of iteration */
                if ( !(--pass) )
                        keepgoing = 0;
@@ -805,6 +872,44 @@ console_initcall(mpc52xx_console_init);
 #define MPC52xx_PSC_CONSOLE NULL
 #endif
 
+#ifdef CONFIG_SERIAL_RS485
+/* ======================================================================== */
+/* SYSFS operations                                                         */
+/* ======================================================================== */
+
+static ssize_t read_uartmode(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf)
+{
+       struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
+
+       printk("Type ttyPSC%i: %i\n", port->line,*(int *)port->private_data);
+       return strlen(buf)+1;
+}
+
+static ssize_t write_uartmode(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev);
+
+       uartmode = simple_strtoul(buf, NULL, 0);
+       
+       if (!uart_console(port)){
+               if (uartmode || *(int *)port->private_data)
+                       *(int *)port->private_data = uartmode;
+               printk("Type ttyPSC%i: %i\n", port->line,
+               *(int *)port->private_data);
+       } else  
+               printk("ttyPSC%i is console\n",port->line);
+               
+       uartmode = RS232;
+       
+       return strlen (buf) + 1;
+}
+
+static DEVICE_ATTR(uartmode, S_IRUGO|S_IWUGO, read_uartmode, write_uartmode);
+#endif /* CONFIG_SERIAL_RS485 */
 
 /* ======================================================================== */
 /* UART Driver                                                              */
@@ -969,6 +1074,19 @@ mpc52xx_uart_of_probe(struct of_device *
        port->ops       = &mpc52xx_uart_ops;
        port->dev       = &op->dev;
 
+       /* to change uart mode, we need a entry point */
+#ifdef CONFIG_SERIAL_RS485
+       device_create_file(&op->dev, &dev_attr_uartmode);
+
+       /* for each port we have to allocate a variable */
+       port->private_data = kmalloc(sizeof(int), GFP_USER);
+       if (!port->private_data)
+               return -ENOMEM;
+
+       *(int *)port->private_data = RS232;
+
+#endif /* CONFIG_SERIAL_RS485 */
+
        /* Search for IRQ and mapbase */
        if ((ret = of_address_to_resource(op->node, 0, &res)) != 0)
                return ret;
@@ -997,6 +1115,13 @@ mpc52xx_uart_of_remove(struct of_device 
 {
        struct uart_port *port = dev_get_drvdata(&op->dev);
        dev_set_drvdata(&op->dev, NULL);
+       
+#ifdef CONFIG_SERIAL_RS485
+       device_remove_file(&op->dev, &dev_attr_uartmode);
+
+       /* Don't forget to free memory */
+       kfree(port->private_data);
+#endif /* CONFIG_SERIAL_RS485 */
 
        if (port) {
                uart_remove_one_port(&mpc52xx_uart_driver, port);
@@ -1132,6 +1257,7 @@ mpc52xx_uart_init(void)
                return ret;
        }
 #else
+
        ret = platform_driver_register(&mpc52xx_uart_platform_driver);
        if (ret) {
                printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
diff -uprN 
linux-2.6.24.7-el392-rt11-can751_org/include/asm-powerpc/mpc52xx_psc.h 
linux-2.6.24.7-el392-rt11-can751/include/asm-powerpc/mpc52xx_psc.h
--- linux-2.6.24.7-el392-rt11-can751_org/include/asm-powerpc/mpc52xx_psc.h      
2008-10-16 13:35:05.000000000 +0200
+++ linux-2.6.24.7-el392-rt11-can751/include/asm-powerpc/mpc52xx_psc.h  
2008-11-14 11:40:56.000000000 +0100
@@ -27,6 +27,7 @@
 /* Max number of PSCs */
 #define MPC52xx_PSC_MAXNUM     6
 
+
 /* Programmable Serial Controller (PSC) status register bits */
 #define MPC52xx_PSC_SR_CDE     0x0080
 #define MPC52xx_PSC_SR_RXRDY   0x0100
@@ -64,6 +65,7 @@
 #define MPC52xx_PSC_IMR_TXRDY          0x0100
 #define MPC52xx_PSC_IMR_RXRDY          0x0200
 #define MPC52xx_PSC_IMR_DB             0x0400
+#define MPC52xx_PSC_IMR_TXEMP          MPC52xx_PSC_SR_TXEMP
 #define MPC52xx_PSC_IMR_IPC            0x8000
 
 /* PSC input port change bit */
@@ -139,8 +141,10 @@ struct mpc52xx_psc {
        u8              ip;             /* PSC + 0x34 */
        u8              reserved9[3];
        u8              op1;            /* PSC + 0x38 */
+#define mpc52xx_psc_op1                op1
        u8              reserved10[3];
        u8              op0;            /* PSC + 0x3c */
+#define mpc52xx_psc_op0                op0
        u8              reserved11[3];
        u32             sicr;           /* PSC + 0x40 */
        u8              ircr1;          /* PSC + 0x44 */
 



Mit freundlichen Grüßen

Hans Lehmann
Softwareentwicklung

Telefon +49 (0)2191-67-2520
Fax     +49 (0)2191-67-703408
e-mail  [EMAIL PROTECTED]



Ritter Elektronik GmbH
Leverkuser Straße 65
D-42897 Remscheid
www.ritter-elektronik.de

Geschäftsführer: Manfred A. Wagner, Dr. Uwe Baader
Sitz der Gesellschaft: Oberhausen
HRB 17168 Duisburg  /  USt-ID DE 814009849


-----Ursprüngliche Nachricht-----
Von: Wolfram Sang [mailto:[EMAIL PROTECTED] 
Gesendet: Donnerstag, 13. November 2008 19:42
An: Lehmann, Hans (Ritter Elektronik)
Cc: linuxppc-dev@ozlabs.org; Grant Likely
Betreff: Re: [PATCH v1] RS485 support for MPC5200x_psc_uart

Hello Hans,

On Thu, Nov 13, 2008 at 04:48:30PM +0100, Lehmann, Hans (Ritter Elektronik) 
wrote:

> Adds rs485 support for MPC52xx_psc_uart

Please be more specific. What exactly was done/modified to have RS485-support.

Please also read SubmittingPatches and CodingStyle in the Documentation 
directory and adapt your patch accordingly. For example: Send patches inlined, 
this makes reviewing a lot easier. Don't use magic numbers. Use spaces around 
operators. All this helps maintaining your code in the future.

> COM1 is console and not selectable.

COM1 is rarely selectable in Linux ;)

Kind regards,

   Wolfram

--
  Dipl.-Ing. Wolfram Sang | http://www.pengutronix.de  Pengutronix - Linux 
Solutions for Science and Industry

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to