#include <linux/serial_core.h>
 #include <linux/8250_pci.h>
 #include <linux/bitops.h>
+#include <linux/bitfield.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
 
 #define MOXA_GPIO_PIN2 BIT(2)
 
+#define MOXA_RS232     0x00
+#define MOXA_RS422     0x01
+#define MOXA_RS485_4W  0x0B
+#define MOXA_RS485_2W  0x0F
+#define MOXA_UIR_OFFSET        0x04
+#define MOXA_EVEN_RS_MASK      GENMASK(3, 0)
+#define MOXA_ODD_RS_MASK       GENMASK(7, 4)
+
+enum {
+       MOXA_SUPP_RS232 = BIT(0),
+       MOXA_SUPP_RS422 = BIT(1),
+       MOXA_SUPP_RS485 = BIT(2),
+};
+
 static bool pci_moxa_is_mini_pcie(unsigned short device)
 {
        if (device == PCI_DEVICE_ID_MOXA_CP102N ||
        return false;
 }
 
+static unsigned int pci_moxa_supported_rs(struct pci_dev *dev)
+{
+       switch (dev->device & 0x0F00) {
+       case 0x0000:
+       case 0x0600:
+               return MOXA_SUPP_RS232;
+       case 0x0100:
+               return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
+       case 0x0300:
+               return MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
+       }
+       return 0;
+}
+
+static int pci_moxa_set_interface(const struct pci_dev *dev,
+                                 unsigned int port_idx,
+                                 u8 mode)
+{
+       resource_size_t iobar_addr = pci_resource_start(dev, 2);
+       resource_size_t UIR_addr = iobar_addr + MOXA_UIR_OFFSET + port_idx / 2;
+       u8 val;
+
+       val = inb(UIR_addr);
+
+       if (port_idx % 2) {
+               val &= ~MOXA_ODD_RS_MASK;
+               val |= FIELD_PREP(MOXA_ODD_RS_MASK, mode);
+       } else {
+               val &= ~MOXA_EVEN_RS_MASK;
+               val |= FIELD_PREP(MOXA_EVEN_RS_MASK, mode);
+       }
+       outb(val, UIR_addr);
+
+       return 0;
+}
+
 static int pci_moxa_init(struct pci_dev *dev)
 {
        unsigned short device = dev->device;
        resource_size_t iobar_addr = pci_resource_start(dev, 2);
-       unsigned int num_ports = (device & 0x00F0) >> 4;
+       unsigned int num_ports = (device & 0x00F0) >> 4, i;
        u8 val;
 
+       if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) {
+               for (i = 0; i < num_ports; ++i)
+                       pci_moxa_set_interface(dev, i, MOXA_RS422);
+       }
+
        /*
         * Enable hardware buffer to prevent break signal output when system boots up.
         * This hardware buffer is only supported on Mini PCIe series.