Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: exar: split out the exar code from 8250_pci

Add the serial driver for the Exar chips. And also register the
platform device for the GPIO provided by the Exar chips.

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Sudip Mukherjee and committed by
Greg Kroah-Hartman
d0aeaa83 bc2be239

+401
+396
drivers/tty/serial/8250/8250_exar.c
··· 1 + /* 2 + * Probe module for 8250/16550-type Exar chips PCI serial ports. 3 + * 4 + * Based on drivers/tty/serial/8250/8250_pci.c, 5 + * 6 + * Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved. 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License. 11 + */ 12 + #include <linux/io.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/pci.h> 16 + #include <linux/serial_core.h> 17 + #include <linux/serial_reg.h> 18 + #include <linux/slab.h> 19 + #include <linux/string.h> 20 + #include <linux/tty.h> 21 + #include <linux/8250_pci.h> 22 + 23 + #include <asm/byteorder.h> 24 + 25 + #include "8250.h" 26 + 27 + #define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020 28 + #define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021 29 + #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 30 + #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 31 + #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 32 + 33 + #define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */ 34 + #define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */ 35 + #define UART_EXAR_MPIO3T_7_0 0x91 /* MPIO3T[7:0] */ 36 + #define UART_EXAR_MPIOINV_7_0 0x92 /* MPIOINV[7:0] */ 37 + #define UART_EXAR_MPIOSEL_7_0 0x93 /* MPIOSEL[7:0] */ 38 + #define UART_EXAR_MPIOOD_7_0 0x94 /* MPIOOD[7:0] */ 39 + #define UART_EXAR_MPIOINT_15_8 0x95 /* MPIOINT[15:8] */ 40 + #define UART_EXAR_MPIOLVL_15_8 0x96 /* MPIOLVL[15:8] */ 41 + #define UART_EXAR_MPIO3T_15_8 0x97 /* MPIO3T[15:8] */ 42 + #define UART_EXAR_MPIOINV_15_8 0x98 /* MPIOINV[15:8] */ 43 + #define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */ 44 + #define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */ 45 + 46 + struct exar8250; 47 + 48 + /** 49 + * struct exar8250_board - board information 50 + * @num_ports: number of serial ports 51 + * @reg_shift: describes UART register mapping in PCI memory 52 + */ 53 + struct exar8250_board { 54 + unsigned int num_ports; 55 + unsigned int reg_shift; 56 + bool has_slave; 57 + int (*setup)(struct exar8250 *, struct pci_dev *, 58 + struct uart_8250_port *, int); 59 + void (*exit)(struct pci_dev *pcidev); 60 + }; 61 + 62 + struct exar8250 { 63 + unsigned int nr; 64 + struct exar8250_board *board; 65 + int line[0]; 66 + }; 67 + 68 + static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, 69 + int idx, unsigned int offset, 70 + struct uart_8250_port *port) 71 + { 72 + const struct exar8250_board *board = priv->board; 73 + unsigned int bar = 0; 74 + 75 + port->port.iotype = UPIO_MEM; 76 + port->port.mapbase = pci_resource_start(pcidev, bar) + offset; 77 + port->port.membase = pcim_iomap_table(pcidev)[bar] + offset; 78 + port->port.regshift = board->reg_shift; 79 + 80 + return 0; 81 + } 82 + 83 + static int 84 + pci_connect_tech_setup(struct exar8250 *priv, struct pci_dev *pcidev, 85 + struct uart_8250_port *port, int idx) 86 + { 87 + unsigned int offset = idx * 0x200; 88 + unsigned int baud = 1843200; 89 + 90 + port->port.uartclk = baud * 16; 91 + return default_setup(priv, pcidev, idx, offset, port); 92 + } 93 + 94 + static int 95 + pci_xr17c154_setup(struct exar8250 *priv, struct pci_dev *pcidev, 96 + struct uart_8250_port *port, int idx) 97 + { 98 + unsigned int offset = idx * 0x200; 99 + unsigned int baud = 921600; 100 + 101 + port->port.uartclk = baud * 16; 102 + return default_setup(priv, pcidev, idx, offset, port); 103 + } 104 + 105 + static void setup_gpio(u8 __iomem *p) 106 + { 107 + writeb(0x00, p + UART_EXAR_MPIOINT_7_0); 108 + writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); 109 + writeb(0x00, p + UART_EXAR_MPIO3T_7_0); 110 + writeb(0x00, p + UART_EXAR_MPIOINV_7_0); 111 + writeb(0x00, p + UART_EXAR_MPIOSEL_7_0); 112 + writeb(0x00, p + UART_EXAR_MPIOOD_7_0); 113 + writeb(0x00, p + UART_EXAR_MPIOINT_15_8); 114 + writeb(0x00, p + UART_EXAR_MPIOLVL_15_8); 115 + writeb(0x00, p + UART_EXAR_MPIO3T_15_8); 116 + writeb(0x00, p + UART_EXAR_MPIOINV_15_8); 117 + writeb(0x00, p + UART_EXAR_MPIOSEL_15_8); 118 + writeb(0x00, p + UART_EXAR_MPIOOD_15_8); 119 + } 120 + 121 + static void * 122 + xr17v35x_register_gpio(struct pci_dev *pcidev) 123 + { 124 + struct platform_device *pdev; 125 + 126 + pdev = platform_device_alloc("gpio_exar", PLATFORM_DEVID_AUTO); 127 + if (!pdev) 128 + return NULL; 129 + 130 + platform_set_drvdata(pdev, pcidev); 131 + if (platform_device_add(pdev) < 0) { 132 + platform_device_put(pdev); 133 + return NULL; 134 + } 135 + 136 + return pdev; 137 + } 138 + 139 + static int 140 + pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, 141 + struct uart_8250_port *port, int idx) 142 + { 143 + const struct exar8250_board *board = priv->board; 144 + unsigned int offset = idx * 0x400; 145 + unsigned int baud = 7812500; 146 + u8 __iomem *p; 147 + int ret; 148 + 149 + port->port.uartclk = baud * 16; 150 + /* 151 + * Setup the uart clock for the devices on expansion slot to 152 + * half the clock speed of the main chip (which is 125MHz) 153 + */ 154 + if (board->has_slave && idx >= 8) 155 + port->port.uartclk /= 2; 156 + 157 + p = pci_ioremap_bar(pcidev, 0); 158 + if (!p) 159 + return -ENOMEM; 160 + 161 + /* Setup Multipurpose Input/Output pins. */ 162 + if (idx == 0) 163 + setup_gpio(p); 164 + 165 + writeb(0x00, p + UART_EXAR_8XMODE); 166 + writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR); 167 + writeb(128, p + UART_EXAR_TXTRG); 168 + writeb(128, p + UART_EXAR_RXTRG); 169 + iounmap(p); 170 + 171 + ret = default_setup(priv, pcidev, idx, offset, port); 172 + if (ret) 173 + return ret; 174 + 175 + if (idx == 0) 176 + port->port.private_data = 177 + xr17v35x_register_gpio(pcidev); 178 + 179 + return 0; 180 + } 181 + 182 + static void pci_xr17v35x_exit(struct pci_dev *pcidev) 183 + { 184 + struct exar8250 *priv = pci_get_drvdata(pcidev); 185 + struct uart_8250_port *port = serial8250_get_port(priv->line[0]); 186 + struct platform_device *pdev = port->port.private_data; 187 + 188 + platform_device_unregister(pdev); 189 + port->port.private_data = NULL; 190 + } 191 + 192 + static int 193 + exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) 194 + { 195 + unsigned int nr_ports, i, bar = 0, maxnr; 196 + struct exar8250_board *board; 197 + struct uart_8250_port uart; 198 + struct exar8250 *priv; 199 + int rc; 200 + 201 + board = (struct exar8250_board *)ent->driver_data; 202 + if (!board) 203 + return -EINVAL; 204 + 205 + rc = pcim_enable_device(pcidev); 206 + if (rc) 207 + return rc; 208 + 209 + maxnr = pci_resource_len(pcidev, bar) >> (board->reg_shift + 3); 210 + 211 + nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f; 212 + 213 + priv = devm_kzalloc(&pcidev->dev, sizeof(*priv) + 214 + sizeof(unsigned int) * nr_ports, 215 + GFP_KERNEL); 216 + if (!priv) 217 + return -ENOMEM; 218 + 219 + priv->board = board; 220 + 221 + memset(&uart, 0, sizeof(uart)); 222 + uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ 223 + | UPF_EXAR_EFR; 224 + uart.port.irq = pcidev->irq; 225 + uart.port.dev = &pcidev->dev; 226 + 227 + for (i = 0; i < nr_ports && i < maxnr; i++) { 228 + rc = board->setup(priv, pcidev, &uart, i); 229 + if (rc) { 230 + dev_err(&pcidev->dev, "Failed to setup port %u\n", i); 231 + break; 232 + } 233 + 234 + dev_dbg(&pcidev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", 235 + uart.port.iobase, uart.port.irq, uart.port.iotype); 236 + 237 + priv->line[i] = serial8250_register_8250_port(&uart); 238 + if (priv->line[i] < 0) { 239 + dev_err(&pcidev->dev, 240 + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", 241 + uart.port.iobase, uart.port.irq, 242 + uart.port.iotype, priv->line[i]); 243 + break; 244 + } 245 + } 246 + priv->nr = i; 247 + pci_set_drvdata(pcidev, priv); 248 + return 0; 249 + } 250 + 251 + static void exar_pci_remove(struct pci_dev *pcidev) 252 + { 253 + struct exar8250 *priv = pci_get_drvdata(pcidev); 254 + unsigned int i; 255 + 256 + for (i = 0; i < priv->nr; i++) 257 + serial8250_unregister_port(priv->line[i]); 258 + 259 + if (priv->board->exit) 260 + priv->board->exit(pcidev); 261 + } 262 + 263 + static int __maybe_unused exar_suspend(struct device *dev) 264 + { 265 + struct pci_dev *pcidev = to_pci_dev(dev); 266 + struct exar8250 *priv = pci_get_drvdata(pcidev); 267 + unsigned int i; 268 + 269 + for (i = 0; i < priv->nr; i++) 270 + if (priv->line[i] >= 0) 271 + serial8250_suspend_port(priv->line[i]); 272 + 273 + /* Ensure that every init quirk is properly torn down */ 274 + if (priv->board->exit) 275 + priv->board->exit(pcidev); 276 + 277 + return 0; 278 + } 279 + 280 + static int __maybe_unused exar_resume(struct device *dev) 281 + { 282 + struct pci_dev *pcidev = to_pci_dev(dev); 283 + struct exar8250 *priv = pci_get_drvdata(pcidev); 284 + unsigned int i; 285 + 286 + for (i = 0; i < priv->nr; i++) 287 + if (priv->line[i] >= 0) 288 + serial8250_resume_port(priv->line[i]); 289 + 290 + return 0; 291 + } 292 + 293 + static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); 294 + 295 + static const struct exar8250_board pbn_connect = { 296 + .setup = pci_connect_tech_setup, 297 + }; 298 + 299 + static const struct exar8250_board pbn_exar_ibm_saturn = { 300 + .num_ports = 1, 301 + .setup = pci_xr17c154_setup, 302 + }; 303 + 304 + static const struct exar8250_board pbn_exar_XR17C15x = { 305 + .setup = pci_xr17c154_setup, 306 + }; 307 + 308 + static const struct exar8250_board pbn_exar_XR17V35x = { 309 + .setup = pci_xr17v35x_setup, 310 + .exit = pci_xr17v35x_exit, 311 + }; 312 + 313 + static const struct exar8250_board pbn_exar_XR17V4358 = { 314 + .num_ports = 12, 315 + .has_slave = true, 316 + .setup = pci_xr17v35x_setup, 317 + .exit = pci_xr17v35x_exit, 318 + }; 319 + 320 + static const struct exar8250_board pbn_exar_XR17V8358 = { 321 + .num_ports = 16, 322 + .has_slave = true, 323 + .setup = pci_xr17v35x_setup, 324 + .exit = pci_xr17v35x_exit, 325 + }; 326 + 327 + #define CONNECT_DEVICE(devid, sdevid, bd) { \ 328 + PCI_DEVICE_SUB( \ 329 + PCI_VENDOR_ID_EXAR, \ 330 + PCI_DEVICE_ID_EXAR_##devid, \ 331 + PCI_SUBVENDOR_ID_CONNECT_TECH, \ 332 + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_##sdevid), 0, 0, \ 333 + (kernel_ulong_t)&bd \ 334 + } 335 + 336 + #define EXAR_DEVICE(vend, devid, bd) { \ 337 + PCI_VDEVICE(vend, PCI_DEVICE_ID_##devid), (kernel_ulong_t)&bd \ 338 + } 339 + 340 + #define IBM_DEVICE(devid, sdevid, bd) { \ 341 + PCI_DEVICE_SUB( \ 342 + PCI_VENDOR_ID_EXAR, \ 343 + PCI_DEVICE_ID_EXAR_##devid, \ 344 + PCI_VENDOR_ID_IBM, \ 345 + PCI_SUBDEVICE_ID_IBM_##sdevid), 0, 0, \ 346 + (kernel_ulong_t)&bd \ 347 + } 348 + 349 + static struct pci_device_id exar_pci_tbl[] = { 350 + CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), 351 + CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), 352 + CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect), 353 + CONNECT_DEVICE(XR17C152, UART_1_1, pbn_connect), 354 + CONNECT_DEVICE(XR17C154, UART_2_2, pbn_connect), 355 + CONNECT_DEVICE(XR17C158, UART_4_4, pbn_connect), 356 + CONNECT_DEVICE(XR17C152, UART_2, pbn_connect), 357 + CONNECT_DEVICE(XR17C154, UART_4, pbn_connect), 358 + CONNECT_DEVICE(XR17C158, UART_8, pbn_connect), 359 + CONNECT_DEVICE(XR17C152, UART_2_485, pbn_connect), 360 + CONNECT_DEVICE(XR17C154, UART_4_485, pbn_connect), 361 + CONNECT_DEVICE(XR17C158, UART_8_485, pbn_connect), 362 + 363 + IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), 364 + 365 + /* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */ 366 + EXAR_DEVICE(EXAR, EXAR_XR17C152, pbn_exar_XR17C15x), 367 + EXAR_DEVICE(EXAR, EXAR_XR17C154, pbn_exar_XR17C15x), 368 + EXAR_DEVICE(EXAR, EXAR_XR17C158, pbn_exar_XR17C15x), 369 + 370 + /* Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */ 371 + EXAR_DEVICE(EXAR, EXAR_XR17V352, pbn_exar_XR17V35x), 372 + EXAR_DEVICE(EXAR, EXAR_XR17V354, pbn_exar_XR17V35x), 373 + EXAR_DEVICE(EXAR, EXAR_XR17V358, pbn_exar_XR17V35x), 374 + EXAR_DEVICE(EXAR, EXAR_XR17V4358, pbn_exar_XR17V4358), 375 + EXAR_DEVICE(EXAR, EXAR_XR17V8358, pbn_exar_XR17V8358), 376 + EXAR_DEVICE(COMMTECH, COMMTECH_4222PCIE, pbn_exar_XR17V35x), 377 + EXAR_DEVICE(COMMTECH, COMMTECH_4224PCIE, pbn_exar_XR17V35x), 378 + EXAR_DEVICE(COMMTECH, COMMTECH_4228PCIE, pbn_exar_XR17V35x), 379 + { 0, } 380 + }; 381 + MODULE_DEVICE_TABLE(pci, exar_pci_tbl); 382 + 383 + static struct pci_driver exar_pci_driver = { 384 + .name = "exar_serial", 385 + .probe = exar_pci_probe, 386 + .remove = exar_pci_remove, 387 + .driver = { 388 + .pm = &exar_pci_pm, 389 + }, 390 + .id_table = exar_pci_tbl, 391 + }; 392 + module_pci_driver(exar_pci_driver); 393 + 394 + MODULE_LICENSE("GPL"); 395 + MODULE_DESCRIPTION("Exar Serial Dricer"); 396 + MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
+4
drivers/tty/serial/8250/Kconfig
··· 127 127 Note that serial ports on NetMos 9835 Multi-I/O cards are handled 128 128 by the parport_serial driver, enabled with CONFIG_PARPORT_SERIAL. 129 129 130 + config SERIAL_8250_EXAR 131 + tristate "8250/16550 PCI device support" 132 + depends on SERIAL_8250_PCI 133 + 130 134 config SERIAL_8250_HP300 131 135 tristate 132 136 depends on SERIAL_8250 && HP300
+1
drivers/tty/serial/8250/Makefile
··· 10 10 8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o 11 11 obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o 12 12 obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o 13 + obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o 13 14 obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o 14 15 obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o 15 16 obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o