|
@@ -10,6 +10,7 @@
|
|
* the Free Software Foundation; either version 2 of the License.
|
|
* the Free Software Foundation; either version 2 of the License.
|
|
*/
|
|
*/
|
|
#include <linux/acpi.h>
|
|
#include <linux/acpi.h>
|
|
|
|
+#include <linux/dmi.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
@@ -62,6 +63,43 @@
|
|
#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */
|
|
#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */
|
|
#define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[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 - <reserved>
|
|
|
|
+ * 4 3 Mode bit 0
|
|
|
|
+ * 5 3 Mode bit 1
|
|
|
|
+ * 6 3 Terminate bus
|
|
|
|
+ * 7 - <reserved>
|
|
|
|
+ * 8 2 Enable
|
|
|
|
+ * 9 3 Enable
|
|
|
|
+ * 10 - Red LED
|
|
|
|
+ * 11..15 - <unused>
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+/* 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;
|
|
struct exar8250;
|
|
|
|
|
|
struct exar8250_platform {
|
|
struct exar8250_platform {
|
|
@@ -236,18 +274,107 @@ static const struct exar8250_platform exar8250_default_platform = {
|
|
.register_gpio = xr17v35x_register_gpio,
|
|
.register_gpio = xr17v35x_register_gpio,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static int iot2040_rs485_config(struct uart_port *port,
|
|
|
|
+ struct serial_rs485 *rs485)
|
|
|
|
+{
|
|
|
|
+ bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
|
|
|
|
+ u8 __iomem *p = port->membase;
|
|
|
|
+ u8 mask = IOT2040_UART1_MASK;
|
|
|
|
+ u8 mode, value;
|
|
|
|
+
|
|
|
|
+ if (is_rs485) {
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ port->rs485 = *rs485;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct property_entry iot2040_gpio_properties[] = {
|
|
|
|
+ PROPERTY_ENTRY_U32("linux,first-pin", 10),
|
|
|
|
+ PROPERTY_ENTRY_U32("ngpios", 1),
|
|
|
|
+ { }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int iot2040_register_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, iot2040_gpio_properties);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct exar8250_platform iot2040_platform = {
|
|
|
|
+ .rs485_config = iot2040_rs485_config,
|
|
|
|
+ .register_gpio = iot2040_register_gpio,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct dmi_system_id exar_platforms[] = {
|
|
|
|
+ {
|
|
|
|
+ .matches = {
|
|
|
|
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
|
|
|
|
+ DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
|
|
|
|
+ "6ES7647-0AA00-1YA2"),
|
|
|
|
+ },
|
|
|
|
+ .driver_data = (void *)&iot2040_platform,
|
|
|
|
+ },
|
|
|
|
+ {}
|
|
|
|
+};
|
|
|
|
+
|
|
static int
|
|
static int
|
|
pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
|
pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
|
struct uart_8250_port *port, int idx)
|
|
struct uart_8250_port *port, int idx)
|
|
{
|
|
{
|
|
const struct exar8250_board *board = priv->board;
|
|
const struct exar8250_board *board = priv->board;
|
|
const struct exar8250_platform *platform;
|
|
const struct exar8250_platform *platform;
|
|
|
|
+ const struct dmi_system_id *dmi_match;
|
|
unsigned int offset = idx * 0x400;
|
|
unsigned int offset = idx * 0x400;
|
|
unsigned int baud = 7812500;
|
|
unsigned int baud = 7812500;
|
|
u8 __iomem *p;
|
|
u8 __iomem *p;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- platform = &exar8250_default_platform;
|
|
|
|
|
|
+ dmi_match = dmi_first_match(exar_platforms);
|
|
|
|
+ if (dmi_match)
|
|
|
|
+ platform = dmi_match->driver_data;
|
|
|
|
+ else
|
|
|
|
+ platform = &exar8250_default_platform;
|
|
|
|
|
|
port->port.uartclk = baud * 16;
|
|
port->port.uartclk = baud * 16;
|
|
port->port.rs485_config = platform->rs485_config;
|
|
port->port.rs485_config = platform->rs485_config;
|