From patchwork Sat May 13 07:29:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 761954 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3wPzHk1W6jz9s75 for ; Sat, 13 May 2017 17:39:14 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751428AbdEMHjN (ORCPT ); Sat, 13 May 2017 03:39:13 -0400 Received: from goliath.siemens.de ([192.35.17.28]:39552 "EHLO goliath.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750935AbdEMHjN (ORCPT ); Sat, 13 May 2017 03:39:13 -0400 X-Greylist: delayed 591 seconds by postgrey-1.27 at vger.kernel.org; Sat, 13 May 2017 03:39:09 EDT Received: from mail3.siemens.de (mail3.siemens.de [139.25.208.14]) by goliath.siemens.de (8.15.2/8.15.2) with ESMTPS id v4D7TCHe012501 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 13 May 2017 09:29:12 +0200 Received: from localhost.localdomain ([146.254.78.19]) by mail3.siemens.de (8.15.2/8.15.2) with ESMTP id v4D7T8NI030047; Sat, 13 May 2017 09:29:11 +0200 From: Jan Kiszka To: Greg Kroah-Hartman , Linus Walleij , Alexandre Courbot Cc: Linux Kernel Mailing List , linux-serial@vger.kernel.org, linux-gpio@vger.kernel.org, Sudip Mukherjee , Andy Shevchenko , Sascha Weisenberger Subject: [PATCH 8/8] serial: exar: Add support for IOT2040 device Date: Sat, 13 May 2017 09:29:06 +0200 Message-Id: <1d8ba1dea24da541389e8175097aa4f67eddc298.1494660546.git.jan.kiszka@siemens.com> X-Mailer: git-send-email 2.12.0 In-Reply-To: References: In-Reply-To: References: Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org This implements the setup of RS232 and the switch-over to RS485 or RS422 for the Siemens IOT2040. That uses an EXAR XR17V352 with external logic to switch between the different modes. The external logic is controlled via MPIO pins of the EXAR controller. Only pin 10 can be exported as GPIO on the IOT2040. It is connected to an LED. As the XR17V352 used on the IOT2040 is not equipped with an external EEPROM, it cannot present itself as IOT2040-variant via subvendor/ subdevice IDs. Thus, we have to check via DMI for the target platform. Co-developed with Sascha Weisenberger. Signed-off-by: Sascha Weisenberger Signed-off-by: Jan Kiszka --- drivers/tty/serial/8250/8250_exar.c | 121 ++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 8e9c0e9495f5..62fe0f1ddcfe 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,43 @@ #define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */ #define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */ +#define UART_EXAR_RS485_DLY(x) (x << 4) + +/* + * IOT2040 MPIO wiring semantics: + * + * MPIO Port Function + * ---- ---- -------- + * 0 2 Mode bit 0 + * 1 2 Mode bit 1 + * 2 2 Terminate bus + * 3 - + * 4 3 Mode bit 0 + * 5 3 Mode bit 1 + * 6 3 Terminate bus + * 7 - + * 8 2 Enable + * 9 3 Enable + * 10 - Red LED + * 11..15 - + */ + +/* IOT2040 MPIOs 0..7 */ +#define IOT2040_UART_MODE_RS232 0x01 +#define IOT2040_UART_MODE_RS485 0x02 +#define IOT2040_UART_MODE_RS422 0x03 +#define IOT2040_UART_TERMINATE_BUS 0x04 + +#define IOT2040_UART1_MASK 0x0f +#define IOT2040_UART2_SHIFT 4 + +#define IOT2040_UARTS_DEFAULT_MODE 0x11 /* both RS232 */ +#define IOT2040_UARTS_GPIO_LO_MODE 0x88 /* reserved pins as input */ + +/* IOT2040 MPIOs 8..15 */ +#define IOT2040_UARTS_ENABLE 0x03 +#define IOT2040_UARTS_GPIO_HI_MODE 0xF8 /* enable & LED as outputs */ + struct exar8250; /** @@ -217,6 +255,65 @@ xr17v35x_register_gpio(struct pci_dev *pcidev, unsigned int first_gpio, return pdev; } +static int iot2040_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 __iomem *p = port->membase; + u8 mask = IOT2040_UART1_MASK; + u8 mode, value; + bool is_rs485 = false; + + if (rs485->flags & SER_RS485_ENABLED) { + is_rs485 = true; + if (rs485->flags & SER_RS485_RX_DURING_TX) + mode = IOT2040_UART_MODE_RS422; + else + mode = IOT2040_UART_MODE_RS485; + + if (rs485->flags & SER_RS485_TERMINATE_BUS) + mode |= IOT2040_UART_TERMINATE_BUS; + } else { + mode = IOT2040_UART_MODE_RS232; + } + + if (port->line == 3) { + mask <<= IOT2040_UART2_SHIFT; + mode <<= IOT2040_UART2_SHIFT; + } + + value = readb(p + UART_EXAR_MPIOLVL_7_0); + value &= ~mask; + value |= mode; + writeb(value, p + UART_EXAR_MPIOLVL_7_0); + + value = readb(p + UART_EXAR_FCTR); + if (is_rs485) + value |= UART_FCTR_EXAR_485; + else + value &= ~UART_FCTR_EXAR_485; + writeb(value, p + UART_EXAR_FCTR); + + if (is_rs485) + writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); + + return 0; +} + +static int iot2000_setup_gpio(struct pci_dev *pcidev, + struct uart_8250_port *port) +{ + u8 __iomem *p = port->port.membase; + + writeb(IOT2040_UARTS_DEFAULT_MODE, p + UART_EXAR_MPIOLVL_7_0); + writeb(IOT2040_UARTS_GPIO_LO_MODE, p + UART_EXAR_MPIOSEL_7_0); + writeb(IOT2040_UARTS_ENABLE, p + UART_EXAR_MPIOLVL_15_8); + writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8); + + port->port.private_data = xr17v35x_register_gpio(pcidev, 10, 1); + + return 0; +} + static int pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port, int idx) @@ -224,10 +321,20 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, const struct exar8250_board *board = priv->board; unsigned int offset = idx * 0x400; unsigned int baud = 7812500; + bool is_iot2040; u8 __iomem *p; int ret; port->port.uartclk = baud * 16; + + is_iot2040 = + strcmp(dmi_get_system_info(DMI_BOARD_NAME), + "SIMATIC IOT2000") == 0 && + strcmp(dmi_get_system_info(DMI_BOARD_ASSET_TAG), + "6ES7647-0AA00-1YA2") == 0; + if (is_iot2040) + port->port.rs485_config = iot2040_rs485_config; + /* * Setup the uart clock for the devices on expansion slot to * half the clock speed of the main chip (which is 125MHz) @@ -246,14 +353,18 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, writeb(128, p + UART_EXAR_TXTRG); writeb(128, p + UART_EXAR_RXTRG); - if (idx == 0) { - /* Setup Multipurpose Input/Output pins. */ - setup_gpio(p); + if (idx != 0) + return 0; + + /* Setup Multipurpose Input/Output pins. */ + setup_gpio(p); + if (is_iot2040) + ret = iot2000_setup_gpio(pcidev, port); + else port->port.private_data = xr17v35x_register_gpio(pcidev, 0, 16); - } - return 0; + return ret; } static void pci_xr17v35x_exit(struct pci_dev *pcidev)