From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753486AbcGSIAX (ORCPT ); Tue, 19 Jul 2016 04:00:23 -0400 Received: from mail-db5eur01on0118.outbound.protection.outlook.com ([104.47.2.118]:48256 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753442AbcGSIAQ (ORCPT ); Tue, 19 Jul 2016 04:00:16 -0400 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=bhuvanchandra.dv@toradex.com; From: Bhuvanchandra DV To: CC: , , , , , , , , , , "Bhuvanchandra DV" Subject: [PATCH RESEND v2 8/8] tty: serial: fsl_lpuart: Add support for RS-485 Date: Tue, 19 Jul 2016 13:13:10 +0530 Message-ID: <20160719074310.16872-9-bhuvanchandra.dv@toradex.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: <20160719074310.16872-1-bhuvanchandra.dv@toradex.com> References: <20160719074310.16872-1-bhuvanchandra.dv@toradex.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [115.115.243.34] X-ClientProxiedBy: MA1PR01CA0045.INDPRD01.PROD.OUTLOOK.COM (10.164.116.145) To DB6PR0501MB2087.eurprd05.prod.outlook.com (10.168.9.139) X-MS-Office365-Filtering-Correlation-Id: 660db7fa-929d-4ed2-0397-08d3afa895ca X-Microsoft-Exchange-Diagnostics: 1;DB6PR0501MB2087;2:RFNauUXz2iF6FDv3LStWboN7G76juhhBDDy8Rv4J+HN/rWiz2fHR0yUMP7kpEKl288NsaAue9jSwhCYaFjQJXn2X4Z6ELkD0AnXTuAfFYvYuo06HjsvIXs5ZlBLRcuU0FBAR5NdwC868q5GBT3U0RubBIhQXqC92dJfy9ycYU53caFLjcS3eZtQ1AzG5xq3U;3:Kk7VZKfJ4QL8X+hIwatp1E0pcEUQD/1Z2K8+5Rw10xsSsnY3stAB2Bbjldaen2K1dNKOCLnt35dLJvcI6dJ1fE657CJKH+kbb0wnCDe73doB3oBQ0HGUzr+R33VGoeNN;25:RBk5eM2GPcISfGl08U/OgcKuNWxomm45i1ESOJwxKWwyVZre8QS+9AG4Bh0RU+C/8rf+pHvVE1aTmGECciia4iLpzBBIMCwE0JFH/RxZp1FnMt1bBKdnf+Ja5+x+cBxzF7Lqx3ERRRP7+tLsb1ziexdqD5lBVkGe9vyoLVCA5Nuq5zrIIyiis7tOChaDaPDmMlehol347rYqk0+Et04d5OyFb09IJf3iuoI2vUM6C8sv/gXAqTY+oebPMlWC14O9iWaHHA7RdcgIdS4dVBcbuKY5GKWDLE3oUZha7y8/dv0GCd1y5MNlaDyQ7snmHWwNDoD3nYnvE2KKOlX/x5/d8zNCo70T/7CfwklLZWatis8lBtKNYSakFHarufShO00ZHNV1zzOnMl4gWshR62KgeJbeIJB8uF2pKfzeM2C5HFM= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:DB6PR0501MB2087; X-Microsoft-Exchange-Diagnostics: 1;DB6PR0501MB2087;31:rJatuaDwUs8Q0ptjSBpeH9VgIckdYEPzrmeab9q1kj+RaqfSt7Gxi3XR47rJ1jeiywCSwE/NGStwBvv9kPY5BcC3Fyw+8RMGlXTSsrn3jL6XJvwAx+t976qOzCPmxc0VRbl3otybvrVhr+xY8xCyN+EI3+9XKCXUO1mU0CA823FJm9hxMBTlqco48q06BtwTqXMJd6uG1I9n6Rg2HyBMLw==;20:rEnDxgdBW4Bp3tW12WUBj49VmTdR6R5kDKUZQYVh8bQydV7dnE4JK4MqUzXgL7UMVk4+GeiCDmU0xtonVZQCFat8UavgDWM42l76MdBhUM0VHR+4BpVR+BqhGdbwIV8ySg8XRyFLPfxus1/gQBz3XuLhU1oH9hJNOXeB2Z+0lRYtb6CnZ95jNf8O+sCScT29yKGZGj/Gceqg9pqRucv4QsXZHpdwBbCbwvEkwa6HeOQK8eyfW5kW95UlGjsNtCZpueez5GHhYG8rnNa9ayAP5rxzWs1OaVeO3VDi77UbOqbbFtbUMxliJUb+jEe9vmbtmLaZzovZ8y/ap31UzZG/MQ==;4:hpzfSEX1zVCMs48hcBw8O1+EQWvhqfzB+voNu4YQWZ3oWIzS4B1K2ktP3dK5sfhsMHWV/kGLvdetW78veOZy39/m/tNcw4YuaqrKO0IAsmlkwydpt1BL0NgwIY+b2ksw45YgmOi2ZgR5eqYrclY9REqHhtcTDt5L63YhVhylYZVXlkZPXE0et3VSa4AvprUtvnfOaxJEwxAhSUsQmPTG3nz3RFHZWLZJlKQYxH/eicIw1jRhAoCgv+iL8TZWoodSMlaBsHYODFO2ed6FB/fbFHeS458Pos16jnjkw8vXdZdaGXdQeTyXNd8YbShpxd9dx0lgbJBiBWY/vEww0UM4g4A4QbvwCqVt1lvPV9do1zv7Hn5VggrouaRNcEXZnugY X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046);SRVR:DB6PR0501MB2087;BCL:0;PCL:0;RULEID:;SRVR:DB6PR0501MB2087; X-Forefront-PRVS: 000800954F X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6009001)(7916002)(199003)(189002)(77096005)(36756003)(42186005)(69596002)(4001430100002)(19580395003)(86362001)(7736002)(19580405001)(47776003)(5003940100001)(2950100001)(92566002)(50466002)(66066001)(76176999)(50986999)(50226002)(4326007)(48376002)(6116002)(3846002)(1076002)(586003)(97736004)(305945005)(68736007)(189998001)(105586002)(8676002)(110136002)(107886002)(53416004)(101416001)(2906002)(2351001)(81156014)(81166006)(229853001)(106356001)(7846002)(33646002)(217873001);DIR:OUT;SFP:1102;SCL:1;SRVR:DB6PR0501MB2087;H:tdx-in-nb-0014.toradex.ext;FPR:;SPF:None;PTR:InfoNoRecords;A:1;MX:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;DB6PR0501MB2087;23:DvCZ7PnEv0qWWrChdH+iP1lpJMisagYTpr0fH6v?= =?us-ascii?Q?qB5YGRNcMdBSmMlOyi4SJj+ao8cnUujB0uP4uZnb2+ZlslVhj/yMQ8Pfir1w?= =?us-ascii?Q?30Cv00E6stW9L6OTVN29hsHg0Tha+YsM1uFA1gBEYOpjJFSvuwQAA9Y0AnbJ?= =?us-ascii?Q?kb2Csaad4UgW0fCgYqgP0CzxYaUvC2n9cvaxNfndW5ANoyK+yGNsWmYucdrb?= =?us-ascii?Q?nyiN4A0BztvEXV4gKRMd9WrY/Z9OQ5G+AFb1MNyCX8/EJFYMWYepLMYjr0YQ?= =?us-ascii?Q?2PIDD4yoB4QH+m7NqKriO5Jt6eDFlpG/XpCm1Q2G89H/KfX6KHInZfPCyTF9?= =?us-ascii?Q?70v6362/IFhIA9nSsk7Cb+Fn3plhvUIfu9C/RUhIzwp9FUH0yhqdc9kRD69c?= =?us-ascii?Q?/lP7IEzYrV7O30gF+0xbmuN6yKzy5VpocnRqJ8KUn+qcpOvCvqexk88usFhR?= =?us-ascii?Q?vrBhg5zTqJ9LnpKdBX3D3OZIqABRD9SsjcTe+JZLr5E6zs6DtiAslh9y/7/1?= =?us-ascii?Q?TDRigT7291drvrYy7EYW8fAddSXZDFFMEkKjz9PO3swh0NnIMHj0cE0G0ZZK?= =?us-ascii?Q?9nyjNzPEkaMyMalKx8XmUE/YsmFX+Zvo4G7exRu7zSy/Xht8n09uprElf2J/?= =?us-ascii?Q?vQDyFsOmaU0of+2vahqZ8iOw831AxzWlnV7pAT+tK9roMGkYFV5snOOxBFAa?= =?us-ascii?Q?biAx0gjrG1/sylFYgkObY4f+Zg+GlwlL3MFCA1Levx6QYHj6cPaWPiHW+w6i?= =?us-ascii?Q?sy1X2uSUsmy2709tluMW7MxgoF73KzykGBiSWcXdqdhfY/i+ddw695aNsISB?= =?us-ascii?Q?nGxtIk9t2snVToUt69aY/aAuez+2wjb219P9mOkW8ORVcP8yfrjfcQp86mlZ?= =?us-ascii?Q?BEnzyLUOUAaVexU/msri1FdvcD0UFyQDZNwKZQqss1yrwUzWB1JOkBQNYfUg?= =?us-ascii?Q?zbbaSyIelz1I/cTd/r3NnWGuQctx62YUX2AJgnK7bT8b8P2FheBsErKL3U32?= =?us-ascii?Q?18FPEdY8+BCBOb3bQZKI1b1/nBBCVhKwnTuxUsVJhO3lVGFAEsXjWdhjydUA?= =?us-ascii?Q?BTwtTCtDfonKRRAfPxEUw9l6+D2Ebd+Nt6ABdSI8DfeFXP6+GEloeijbcTvm?= =?us-ascii?Q?pG5VsAtlAwd9UeFeBStsEFkAjTljtGkfsqwogdX/grLJp8IxUDRO447J4TWy?= =?us-ascii?Q?PYFh49m7+7K88Xm3mbrKBGD58W7lmp1GZ537y?= X-Microsoft-Exchange-Diagnostics: 1;DB6PR0501MB2087;6:08y0nJHz6V/D68sRvZIf+Jc5ivlbUQL/i7L+0XWiQ2bzDiCr+3I9itbH6zD2hWgNnpdFJ2M9NaI4pbTFbxo3Y5nMYUR8B1rXAD1WxXAEcND0Z5JBaTvoyJiN70kA9GiXTNkcdN/0t9umfRsrbZRy7DObulhuJexwCmCIKQxMXLrwje5zzYE82k3Zzw+iV1rj/viw+0svbrnDIWMYluIXfz1E+L6wsohDdRBVEsFoPKZdYP3m7FYkEBKz2nSXEapWg7nzJgSLfu5AiG7kt2Iha3T18QZvtQvp/E//G49gYos=;5:wekYwqDh9w3N98kNZ9XWfMOQdf67hqgetFkDyXlH+9RM4csrrXctJT0WQJ4xI+5AFeSupANx3dzlujKS4Dz5yV2yvbHshGuWeO6+FFbND1jHaWkZAQxD41CgrMgvCy93soD+8U2jCn/z5H5rLN7/0Q==;24:fy9Bl6XMbZTQqC6UsQv5jQUvRmphjs8xgzOKkzRlXMZ2qVerCDUusYZHWKSjPvWsL7JrEPa+Dh1hMevgUXfldyCTi7+1WHnnjVOXmmb8G8M=;7:tLJqPmbrmojQ6RlhK0sTR2fWXCFB7XbxBeUh1f4bq+zPZ3UJCXmxXH00hh3xBE8QPcUPiJLo4NYh8OG60xzqOH6xB+mG41meF0q2+FX3kAjqD0mDnv0t6UcKM0mYrStWEg4yavk31PRjqcXVAMy+f53TjpN3DX0D3LtUNG5rme+GdgbzdCsyNlpc3lcaaLp2l7VfVbJq//ZM2J7wlZ6WK83MrmiVFUxbC9XQwIwRia5Xqufbp//JGCe4xl1QOohN SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: toradex.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Jul 2016 07:44:56.9664 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0501MB2087 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Enable Vybrid's build-in support for RS-485 auto RTS for controlling line direction of RS-485 transceiver driver. Enable RS485 feature by either using ioctrl 'TIOCSRS485' or enable it in the device tree by setting 'linux,rs485-enabled-at-boot-time' property. Signed-off-by: Bhuvanchandra DV --- drivers/tty/serial/fsl_lpuart.c | 78 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 134090a..4d1fca4 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -917,6 +917,52 @@ static void lpuart_dma_rx_free(struct uart_port *port) sport->dma_rx_cookie = -EINVAL; } +static int lpuart_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + + u8 modem = readb(sport->port.membase + UARTMODEM) & + ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); + writeb(modem, sport->port.membase + UARTMODEM); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ + modem |= UARTMODEM_TXRTSE; + + /* + * RTS needs to be logic HIGH either during transer _or_ after + * transfer, other variants are not supported by the hardware. + */ + + if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND))) + rs485->flags |= SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_RTS_ON_SEND && + rs485->flags & SER_RS485_RTS_AFTER_SEND) + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + + /* + * The hardware defaults to RTS logic HIGH while transfer. + * Switch polarity in case RTS shall be logic HIGH + * after transfer. + * Note: UART is assumed to be active high. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) + modem &= ~UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem |= UARTMODEM_TXRTSPOL; + } + + /* Store the new configuration */ + sport->port.rs485 = *rs485; + + writeb(modem, sport->port.membase + UARTMODEM); + return 0; +} + static unsigned int lpuart_get_mctrl(struct uart_port *port) { unsigned int temp = 0; @@ -950,17 +996,22 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port) static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned char temp; + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); - temp = readb(port->membase + UARTMODEM) & + /* Make sure RXRTSE bit is not set when RS485 is enabled */ + if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) { + temp = readb(sport->port.membase + UARTMODEM) & ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - if (mctrl & TIOCM_RTS) - temp |= UARTMODEM_RXRTSE; + if (mctrl & TIOCM_RTS) + temp |= UARTMODEM_RXRTSE; - if (mctrl & TIOCM_CTS) - temp |= UARTMODEM_TXCTSE; + if (mctrl & TIOCM_CTS) + temp |= UARTMODEM_TXCTSE; - writeb(temp, port->membase + UARTMODEM); + writeb(temp, port->membase + UARTMODEM); + } } static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -1256,6 +1307,13 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, cr1 |= UARTCR1_M; } + /* + * When auto RS-485 RTS mode is enabled, + * hardware flow control need to be disabled. + */ + if (sport->port.rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) { modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); } else { @@ -1864,6 +1922,8 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.ops = &lpuart_pops; sport->port.flags = UPF_BOOT_AUTOCONF; + sport->port.rs485_config = lpuart_config_rs485; + sport->clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk)) { ret = PTR_ERR(sport->clk); @@ -1904,6 +1964,12 @@ static int lpuart_probe(struct platform_device *pdev) dev_info(sport->port.dev, "DMA rx channel request failed, " "operating without rx DMA\n"); + if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) { + sport->port.rs485.flags |= SER_RS485_ENABLED; + sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; + writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM); + } + return 0; } -- 2.9.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Bhuvanchandra DV Subject: [PATCH RESEND v2 8/8] tty: serial: fsl_lpuart: Add support for RS-485 Date: Tue, 19 Jul 2016 13:13:10 +0530 Message-ID: <20160719074310.16872-9-bhuvanchandra.dv@toradex.com> References: <20160719074310.16872-1-bhuvanchandra.dv@toradex.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <20160719074310.16872-1-bhuvanchandra.dv@toradex.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: gregkh@linuxfoundation.org Cc: linux-serial@vger.kernel.org, mturquette@baylibre.com, sboyd@codeaurora.org, linux-kernel@vger.kernel.org, stefan@agner.ch, kernel@pengutronix.de, jslaby@suse.com, shawnguo@kernel.org, linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Bhuvanchandra DV List-Id: linux-serial@vger.kernel.org Enable Vybrid's build-in support for RS-485 auto RTS for controlling line direction of RS-485 transceiver driver. Enable RS485 feature by either using ioctrl 'TIOCSRS485' or enable it in the device tree by setting 'linux,rs485-enabled-at-boot-time' property. Signed-off-by: Bhuvanchandra DV --- drivers/tty/serial/fsl_lpuart.c | 78 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 134090a..4d1fca4 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -917,6 +917,52 @@ static void lpuart_dma_rx_free(struct uart_port *port) sport->dma_rx_cookie = -EINVAL; } +static int lpuart_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + + u8 modem = readb(sport->port.membase + UARTMODEM) & + ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); + writeb(modem, sport->port.membase + UARTMODEM); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ + modem |= UARTMODEM_TXRTSE; + + /* + * RTS needs to be logic HIGH either during transer _or_ after + * transfer, other variants are not supported by the hardware. + */ + + if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND))) + rs485->flags |= SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_RTS_ON_SEND && + rs485->flags & SER_RS485_RTS_AFTER_SEND) + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + + /* + * The hardware defaults to RTS logic HIGH while transfer. + * Switch polarity in case RTS shall be logic HIGH + * after transfer. + * Note: UART is assumed to be active high. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) + modem &= ~UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem |= UARTMODEM_TXRTSPOL; + } + + /* Store the new configuration */ + sport->port.rs485 = *rs485; + + writeb(modem, sport->port.membase + UARTMODEM); + return 0; +} + static unsigned int lpuart_get_mctrl(struct uart_port *port) { unsigned int temp = 0; @@ -950,17 +996,22 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port) static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned char temp; + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); - temp = readb(port->membase + UARTMODEM) & + /* Make sure RXRTSE bit is not set when RS485 is enabled */ + if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) { + temp = readb(sport->port.membase + UARTMODEM) & ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - if (mctrl & TIOCM_RTS) - temp |= UARTMODEM_RXRTSE; + if (mctrl & TIOCM_RTS) + temp |= UARTMODEM_RXRTSE; - if (mctrl & TIOCM_CTS) - temp |= UARTMODEM_TXCTSE; + if (mctrl & TIOCM_CTS) + temp |= UARTMODEM_TXCTSE; - writeb(temp, port->membase + UARTMODEM); + writeb(temp, port->membase + UARTMODEM); + } } static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -1256,6 +1307,13 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, cr1 |= UARTCR1_M; } + /* + * When auto RS-485 RTS mode is enabled, + * hardware flow control need to be disabled. + */ + if (sport->port.rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) { modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); } else { @@ -1864,6 +1922,8 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.ops = &lpuart_pops; sport->port.flags = UPF_BOOT_AUTOCONF; + sport->port.rs485_config = lpuart_config_rs485; + sport->clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk)) { ret = PTR_ERR(sport->clk); @@ -1904,6 +1964,12 @@ static int lpuart_probe(struct platform_device *pdev) dev_info(sport->port.dev, "DMA rx channel request failed, " "operating without rx DMA\n"); + if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) { + sport->port.rs485.flags |= SER_RS485_ENABLED; + sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; + writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM); + } + return 0; } -- 2.9.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: bhuvanchandra.dv@toradex.com (Bhuvanchandra DV) Date: Tue, 19 Jul 2016 13:13:10 +0530 Subject: [PATCH RESEND v2 8/8] tty: serial: fsl_lpuart: Add support for RS-485 In-Reply-To: <20160719074310.16872-1-bhuvanchandra.dv@toradex.com> References: <20160719074310.16872-1-bhuvanchandra.dv@toradex.com> Message-ID: <20160719074310.16872-9-bhuvanchandra.dv@toradex.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Enable Vybrid's build-in support for RS-485 auto RTS for controlling line direction of RS-485 transceiver driver. Enable RS485 feature by either using ioctrl 'TIOCSRS485' or enable it in the device tree by setting 'linux,rs485-enabled-at-boot-time' property. Signed-off-by: Bhuvanchandra DV --- drivers/tty/serial/fsl_lpuart.c | 78 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 134090a..4d1fca4 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -917,6 +917,52 @@ static void lpuart_dma_rx_free(struct uart_port *port) sport->dma_rx_cookie = -EINVAL; } +static int lpuart_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + + u8 modem = readb(sport->port.membase + UARTMODEM) & + ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); + writeb(modem, sport->port.membase + UARTMODEM); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ + modem |= UARTMODEM_TXRTSE; + + /* + * RTS needs to be logic HIGH either during transer _or_ after + * transfer, other variants are not supported by the hardware. + */ + + if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND))) + rs485->flags |= SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_RTS_ON_SEND && + rs485->flags & SER_RS485_RTS_AFTER_SEND) + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + + /* + * The hardware defaults to RTS logic HIGH while transfer. + * Switch polarity in case RTS shall be logic HIGH + * after transfer. + * Note: UART is assumed to be active high. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) + modem &= ~UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem |= UARTMODEM_TXRTSPOL; + } + + /* Store the new configuration */ + sport->port.rs485 = *rs485; + + writeb(modem, sport->port.membase + UARTMODEM); + return 0; +} + static unsigned int lpuart_get_mctrl(struct uart_port *port) { unsigned int temp = 0; @@ -950,17 +996,22 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port) static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned char temp; + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); - temp = readb(port->membase + UARTMODEM) & + /* Make sure RXRTSE bit is not set when RS485 is enabled */ + if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) { + temp = readb(sport->port.membase + UARTMODEM) & ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - if (mctrl & TIOCM_RTS) - temp |= UARTMODEM_RXRTSE; + if (mctrl & TIOCM_RTS) + temp |= UARTMODEM_RXRTSE; - if (mctrl & TIOCM_CTS) - temp |= UARTMODEM_TXCTSE; + if (mctrl & TIOCM_CTS) + temp |= UARTMODEM_TXCTSE; - writeb(temp, port->membase + UARTMODEM); + writeb(temp, port->membase + UARTMODEM); + } } static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -1256,6 +1307,13 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, cr1 |= UARTCR1_M; } + /* + * When auto RS-485 RTS mode is enabled, + * hardware flow control need to be disabled. + */ + if (sport->port.rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) { modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); } else { @@ -1864,6 +1922,8 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.ops = &lpuart_pops; sport->port.flags = UPF_BOOT_AUTOCONF; + sport->port.rs485_config = lpuart_config_rs485; + sport->clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk)) { ret = PTR_ERR(sport->clk); @@ -1904,6 +1964,12 @@ static int lpuart_probe(struct platform_device *pdev) dev_info(sport->port.dev, "DMA rx channel request failed, " "operating without rx DMA\n"); + if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) { + sport->port.rs485.flags |= SER_RS485_ENABLED; + sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; + writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM); + } + return 0; } -- 2.9.0