linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1] RS485 support for MPC5200x_psc_uart
@ 2008-11-13 15:48 Lehmann, Hans (Ritter Elektronik)
  2008-11-13 18:42 ` Wolfram Sang
  0 siblings, 1 reply; 4+ messages in thread
From: Lehmann, Hans (Ritter Elektronik) @ 2008-11-13 15:48 UTC (permalink / raw)
  To: linuxppc-dev, Grant Likely

[-- Attachment #1: Type: text/plain, Size: 784 bytes --]

Maybe usefull for someone

Adds rs485 support for MPC52xx_psc_uart

To change mode: 
echo 1 >/sys/dev/f00000000.soc5200.f0002x000.serial/uartmode

COM1 is console and not selectable.

We choose this way to handle the uart mode by S3 CoDeSys.
I am quite sure this is not the best solution but in our case helpfull 

Cheers


Mit freundlichen Grüßen

Hans Lehmann
Softwareentwicklung

Telefon	+49 (0)2191-67-2520
Fax 	+49 (0)2191-67-703408
e-mail 	hans.lehmann@ritter-elektronik.de

 

Ritter Elektronik GmbH
Leverkuser Straße 65
D-42897 Remscheid
www.ritter-elektronik.de <http://www.ritter-elektronik.de/start.html> 

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



[-- Attachment #2: mpc52xx_rs485_support.patch --]
[-- Type: application/octet-stream, Size: 8315 bytes --]

diff -Naur 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 @@
 	  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 -Naur 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-13 16:16:18.000000000 +0100
@@ -21,11 +21,20 @@
  * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
  * Copyright (C) 2003 MontaVista, Software, Inc.
  *
+ * RS485 support is written by Hans Lehmann 
+ *	<hans.Lehmann@ritter-elektronik.de>
+ *
  * 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
+ */
+
 /* Platform device Usage :
  *
  * Since PSCs can have multiple function, the correct driver for each one
@@ -94,6 +103,9 @@
 
 #define ISR_PASS_LIMIT 256	/* Max number of iteration in the interrupt */
 
+#define	EL392_SET_RTS		0x01
+#define	EL392_CLR_RTS		EL392_SET_RTS
+
 
 static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
 	/* Rem: - We use the read_status_mask as a shadow of
@@ -132,6 +144,9 @@
 };
 #endif
 
+#ifdef CONFIG_SERIAL_RS485
+int uartmode = 0;
+#endif /* CONFIG_SERIAL_RS485 */
 
 /* ======================================================================== */
 /* UART operations                                                          */
@@ -144,6 +159,16 @@
 	return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
 }
 
+#ifdef CONFIG_SERIAL_RS485
+static void
+mpc52xx_uart_rs485_rts_clear(struct uart_port *port)
+{
+	out_8(&PSC(port)->mpc52xx_psc_op0, EL392_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,7 +193,16 @@
 static void
 mpc52xx_uart_start_tx(struct uart_port *port)
 {
-	/* port->lock taken by caller */
+#ifdef CONFIG_SERIAL_RS485
+	if (*(int *)port->private_data){
+		out_8(&PSC(port)->mpc52xx_psc_op1, EL392_CLR_RTS);
+		port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY | MPC52xx_PSC_IMR_TXEMP;
+		out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+	}
+	else
+#endif /* CONFIG_SERIAL_RS485 */
+	
+	/* port->lock taken by caller */	
 	port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
 	out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
 }
@@ -243,7 +277,10 @@
 	out_8(&psc->tfcntl, 0x07);
 	out_be16(&psc->tfalarm, 0x80);
 
-	port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
+	if (port->type == 1 )
+		port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY | MPC52xx_PSC_IMR_TXEMP;
+	else
+		port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
 	out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
 
 	out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
@@ -513,6 +550,14 @@
 {
 	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 +623,11 @@
 		if ( status & MPC52xx_PSC_IMR_TXRDY )
 			keepgoing |= mpc52xx_uart_int_tx_chars(port);
 
+#ifdef CONFIG_SERIAL_RS485
+		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 +855,44 @@
 #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 (port->line > 0){
+		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(KERN_INFO"ttyPSC0 = RS232, ttyPSC1 = RS485\n");
+	
+	uartmode = 0;
+	
+	return strlen(buf)+1;
+}
+
+static DEVICE_ATTR(uartmode, S_IRUGO|S_IWUGO, read_uartmode, write_uartmode);
+#endif /* CONFIG_SERIAL_RS485 */
 
 /* ======================================================================== */
 /* UART Driver                                                              */
@@ -969,6 +1057,16 @@
 	port->ops	= &mpc52xx_uart_ops;
 	port->dev	= &op->dev;
 
+#ifdef CONFIG_SERIAL_RS485
+	device_create_file(&op->dev, &dev_attr_uartmode);
+
+	port->private_data = kmalloc(sizeof(int), GFP_USER);
+	if (!port->private_data)
+		return -ENOMEM;
+
+	*(int *)port->private_data = 0;
+#endif /* CONFIG_SERIAL_RS485 */
+
 	/* Search for IRQ and mapbase */
 	if ((ret = of_address_to_resource(op->node, 0, &res)) != 0)
 		return ret;
@@ -997,6 +1095,12 @@
 {
 	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);
+
+	kfree(port->private_data);
+#endif /* CONFIG_SERIAL_RS485 */
 
 	if (port) {
 		uart_remove_one_port(&mpc52xx_uart_driver, port);
@@ -1132,6 +1236,7 @@
 		return ret;
 	}
 #else
+
 	ret = platform_driver_register(&mpc52xx_uart_platform_driver);
 	if (ret) {
 		printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
 
diff -Naur 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-06 16:45:04.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 @@
 	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 */

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-11-27 22:39 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-13 15:48 [PATCH v1] RS485 support for MPC5200x_psc_uart Lehmann, Hans (Ritter Elektronik)
2008-11-13 18:42 ` Wolfram Sang
2008-11-17 15:27   ` AW: " Lehmann, Hans (Ritter Elektronik)
2008-11-27 22:39     ` Wolfram Sang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).