| /* |
| * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver. |
| * |
| * Author: Mathieu OTHACEHE <m.othacehe@gmail.com> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/pci.h> |
| |
| #include "8250.h" |
| |
| #define PCI_DEVICE_ID_MOXA_CP102E 0x1024 |
| #define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 |
| #define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 |
| #define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 |
| #define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 |
| #define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 |
| #define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 |
| #define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 |
| #define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 |
| #define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 |
| #define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 |
| #define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 |
| |
| #define MOXA_BASE_BAUD 921600 |
| #define MOXA_UART_OFFSET 0x200 |
| #define MOXA_BASE_BAR 1 |
| |
| struct moxa8250_board { |
| unsigned int num_ports; |
| int line[0]; |
| }; |
| |
| enum { |
| moxa8250_2p = 0, |
| moxa8250_4p, |
| moxa8250_8p |
| }; |
| |
| static struct moxa8250_board moxa8250_boards[] = { |
| [moxa8250_2p] = { .num_ports = 2}, |
| [moxa8250_4p] = { .num_ports = 4}, |
| [moxa8250_8p] = { .num_ports = 8}, |
| }; |
| |
| static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| { |
| struct uart_8250_port uart; |
| struct moxa8250_board *brd; |
| void __iomem *ioaddr; |
| resource_size_t baseaddr; |
| unsigned int i, nr_ports; |
| unsigned int offset; |
| int ret; |
| |
| brd = &moxa8250_boards[id->driver_data]; |
| nr_ports = brd->num_ports; |
| |
| ret = pcim_enable_device(pdev); |
| if (ret) |
| return ret; |
| |
| brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) + |
| sizeof(unsigned int) * nr_ports, GFP_KERNEL); |
| if (!brd) |
| return -ENOMEM; |
| |
| memset(&uart, 0, sizeof(struct uart_8250_port)); |
| |
| uart.port.dev = &pdev->dev; |
| uart.port.irq = pdev->irq; |
| uart.port.uartclk = MOXA_BASE_BAUD * 16; |
| uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; |
| |
| baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR); |
| ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0); |
| if (!ioaddr) |
| return -ENOMEM; |
| |
| for (i = 0; i < nr_ports; i++) { |
| |
| /* |
| * MOXA Smartio MUE boards with 4 ports have |
| * a different offset for port #3 |
| */ |
| if (nr_ports == 4 && i == 3) |
| offset = 7 * MOXA_UART_OFFSET; |
| else |
| offset = i * MOXA_UART_OFFSET; |
| |
| uart.port.iotype = UPIO_MEM; |
| uart.port.iobase = 0; |
| uart.port.mapbase = baseaddr + offset; |
| uart.port.membase = ioaddr + offset; |
| uart.port.regshift = 0; |
| |
| dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", |
| uart.port.iobase, uart.port.irq, uart.port.iotype); |
| |
| brd->line[i] = serial8250_register_8250_port(&uart); |
| if (brd->line[i] < 0) { |
| dev_err(&pdev->dev, |
| "Couldn't register serial port %lx, irq %d, type %d, error %d\n", |
| uart.port.iobase, uart.port.irq, |
| uart.port.iotype, brd->line[i]); |
| break; |
| } |
| } |
| |
| pci_set_drvdata(pdev, brd); |
| return 0; |
| } |
| |
| static void moxa8250_remove(struct pci_dev *pdev) |
| { |
| struct moxa8250_board *brd = pci_get_drvdata(pdev); |
| unsigned int i; |
| |
| for (i = 0; i < brd->num_ports; i++) |
| serial8250_unregister_port(brd->line[i]); |
| } |
| |
| #define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data } |
| |
| static const struct pci_device_id pci_ids[] = { |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p), |
| MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p), |
| {0} |
| }; |
| MODULE_DEVICE_TABLE(pci, pci_ids); |
| |
| static struct pci_driver moxa8250_pci_driver = { |
| .name = "8250_moxa", |
| .id_table = pci_ids, |
| .probe = moxa8250_probe, |
| .remove = moxa8250_remove, |
| }; |
| |
| module_pci_driver(moxa8250_pci_driver); |
| |
| MODULE_AUTHOR("Mathieu OTHACEHE"); |
| MODULE_DESCRIPTION("MOXA SmartIO MUE driver"); |
| MODULE_LICENSE("GPL v2"); |