.. | .. |
---|
22 | 22 | #include <linux/serial_core.h> |
---|
23 | 23 | #include <linux/tty_flip.h> |
---|
24 | 24 | #include <linux/types.h> |
---|
| 25 | +#include <linux/idr.h> |
---|
25 | 26 | |
---|
26 | 27 | #define SERIAL_NAME "ttyMPS" |
---|
27 | 28 | #define DRIVER_NAME "mps2-uart" |
---|
.. | .. |
---|
65 | 66 | |
---|
66 | 67 | #define MPS2_MAX_PORTS 3 |
---|
67 | 68 | |
---|
| 69 | +#define UART_PORT_COMBINED_IRQ BIT(0) |
---|
| 70 | + |
---|
68 | 71 | struct mps2_uart_port { |
---|
69 | 72 | struct uart_port port; |
---|
70 | 73 | struct clk *clk; |
---|
71 | 74 | unsigned int tx_irq; |
---|
72 | 75 | unsigned int rx_irq; |
---|
| 76 | + unsigned int flags; |
---|
73 | 77 | }; |
---|
74 | 78 | |
---|
75 | 79 | static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port) |
---|
.. | .. |
---|
264 | 268 | return handled; |
---|
265 | 269 | } |
---|
266 | 270 | |
---|
| 271 | +static irqreturn_t mps2_uart_combinedirq(int irq, void *data) |
---|
| 272 | +{ |
---|
| 273 | + if (mps2_uart_rxirq(irq, data) == IRQ_HANDLED) |
---|
| 274 | + return IRQ_HANDLED; |
---|
| 275 | + |
---|
| 276 | + if (mps2_uart_txirq(irq, data) == IRQ_HANDLED) |
---|
| 277 | + return IRQ_HANDLED; |
---|
| 278 | + |
---|
| 279 | + if (mps2_uart_oerrirq(irq, data) == IRQ_HANDLED) |
---|
| 280 | + return IRQ_HANDLED; |
---|
| 281 | + |
---|
| 282 | + return IRQ_NONE; |
---|
| 283 | +} |
---|
| 284 | + |
---|
267 | 285 | static int mps2_uart_startup(struct uart_port *port) |
---|
268 | 286 | { |
---|
269 | 287 | struct mps2_uart_port *mps_port = to_mps2_port(port); |
---|
.. | .. |
---|
274 | 292 | |
---|
275 | 293 | mps2_uart_write8(port, control, UARTn_CTRL); |
---|
276 | 294 | |
---|
277 | | - ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, |
---|
278 | | - MAKE_NAME(-rx), mps_port); |
---|
279 | | - if (ret) { |
---|
280 | | - dev_err(port->dev, "failed to register rxirq (%d)\n", ret); |
---|
281 | | - return ret; |
---|
282 | | - } |
---|
| 295 | + if (mps_port->flags & UART_PORT_COMBINED_IRQ) { |
---|
| 296 | + ret = request_irq(port->irq, mps2_uart_combinedirq, 0, |
---|
| 297 | + MAKE_NAME(-combined), mps_port); |
---|
283 | 298 | |
---|
284 | | - ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, |
---|
285 | | - MAKE_NAME(-tx), mps_port); |
---|
286 | | - if (ret) { |
---|
287 | | - dev_err(port->dev, "failed to register txirq (%d)\n", ret); |
---|
288 | | - goto err_free_rxirq; |
---|
289 | | - } |
---|
| 299 | + if (ret) { |
---|
| 300 | + dev_err(port->dev, "failed to register combinedirq (%d)\n", ret); |
---|
| 301 | + return ret; |
---|
| 302 | + } |
---|
| 303 | + } else { |
---|
| 304 | + ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED, |
---|
| 305 | + MAKE_NAME(-overrun), mps_port); |
---|
290 | 306 | |
---|
291 | | - ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED, |
---|
292 | | - MAKE_NAME(-overrun), mps_port); |
---|
| 307 | + if (ret) { |
---|
| 308 | + dev_err(port->dev, "failed to register oerrirq (%d)\n", ret); |
---|
| 309 | + return ret; |
---|
| 310 | + } |
---|
293 | 311 | |
---|
294 | | - if (ret) { |
---|
295 | | - dev_err(port->dev, "failed to register oerrirq (%d)\n", ret); |
---|
296 | | - goto err_free_txirq; |
---|
| 312 | + ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, |
---|
| 313 | + MAKE_NAME(-rx), mps_port); |
---|
| 314 | + if (ret) { |
---|
| 315 | + dev_err(port->dev, "failed to register rxirq (%d)\n", ret); |
---|
| 316 | + goto err_free_oerrirq; |
---|
| 317 | + } |
---|
| 318 | + |
---|
| 319 | + ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, |
---|
| 320 | + MAKE_NAME(-tx), mps_port); |
---|
| 321 | + if (ret) { |
---|
| 322 | + dev_err(port->dev, "failed to register txirq (%d)\n", ret); |
---|
| 323 | + goto err_free_rxirq; |
---|
| 324 | + } |
---|
| 325 | + |
---|
297 | 326 | } |
---|
298 | 327 | |
---|
299 | 328 | control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP; |
---|
.. | .. |
---|
302 | 331 | |
---|
303 | 332 | return 0; |
---|
304 | 333 | |
---|
305 | | -err_free_txirq: |
---|
306 | | - free_irq(mps_port->tx_irq, mps_port); |
---|
307 | 334 | err_free_rxirq: |
---|
308 | 335 | free_irq(mps_port->rx_irq, mps_port); |
---|
| 336 | +err_free_oerrirq: |
---|
| 337 | + free_irq(port->irq, mps_port); |
---|
309 | 338 | |
---|
310 | 339 | return ret; |
---|
311 | 340 | } |
---|
.. | .. |
---|
319 | 348 | |
---|
320 | 349 | mps2_uart_write8(port, control, UARTn_CTRL); |
---|
321 | 350 | |
---|
322 | | - free_irq(mps_port->rx_irq, mps_port); |
---|
323 | | - free_irq(mps_port->tx_irq, mps_port); |
---|
| 351 | + if (!(mps_port->flags & UART_PORT_COMBINED_IRQ)) { |
---|
| 352 | + free_irq(mps_port->rx_irq, mps_port); |
---|
| 353 | + free_irq(mps_port->tx_irq, mps_port); |
---|
| 354 | + } |
---|
| 355 | + |
---|
324 | 356 | free_irq(port->irq, mps_port); |
---|
325 | 357 | } |
---|
326 | 358 | |
---|
.. | .. |
---|
397 | 429 | .verify_port = mps2_uart_verify_port, |
---|
398 | 430 | }; |
---|
399 | 431 | |
---|
400 | | -static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS]; |
---|
| 432 | +static DEFINE_IDR(ports_idr); |
---|
401 | 433 | |
---|
402 | 434 | #ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE |
---|
403 | 435 | static void mps2_uart_console_putchar(struct uart_port *port, int ch) |
---|
.. | .. |
---|
410 | 442 | |
---|
411 | 443 | static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt) |
---|
412 | 444 | { |
---|
413 | | - struct uart_port *port = &mps2_uart_ports[co->index].port; |
---|
| 445 | + struct mps2_uart_port *mps_port = idr_find(&ports_idr, co->index); |
---|
| 446 | + struct uart_port *port = &mps_port->port; |
---|
414 | 447 | |
---|
415 | 448 | uart_console_write(port, s, cnt, mps2_uart_console_putchar); |
---|
416 | 449 | } |
---|
.. | .. |
---|
426 | 459 | if (co->index < 0 || co->index >= MPS2_MAX_PORTS) |
---|
427 | 460 | return -ENODEV; |
---|
428 | 461 | |
---|
429 | | - mps_port = &mps2_uart_ports[co->index]; |
---|
| 462 | + mps_port = idr_find(&ports_idr, co->index); |
---|
| 463 | + |
---|
| 464 | + if (!mps_port) |
---|
| 465 | + return -ENODEV; |
---|
430 | 466 | |
---|
431 | 467 | if (options) |
---|
432 | 468 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
---|
.. | .. |
---|
487 | 523 | .cons = MPS2_SERIAL_CONSOLE, |
---|
488 | 524 | }; |
---|
489 | 525 | |
---|
490 | | -static struct mps2_uart_port *mps2_of_get_port(struct platform_device *pdev) |
---|
| 526 | +static int mps2_of_get_port(struct platform_device *pdev, |
---|
| 527 | + struct mps2_uart_port *mps_port) |
---|
491 | 528 | { |
---|
492 | 529 | struct device_node *np = pdev->dev.of_node; |
---|
493 | 530 | int id; |
---|
494 | 531 | |
---|
495 | 532 | if (!np) |
---|
496 | | - return NULL; |
---|
| 533 | + return -ENODEV; |
---|
497 | 534 | |
---|
498 | 535 | id = of_alias_get_id(np, "serial"); |
---|
| 536 | + |
---|
499 | 537 | if (id < 0) |
---|
500 | | - id = 0; |
---|
| 538 | + id = idr_alloc_cyclic(&ports_idr, (void *)mps_port, 0, MPS2_MAX_PORTS, GFP_KERNEL); |
---|
| 539 | + else |
---|
| 540 | + id = idr_alloc(&ports_idr, (void *)mps_port, id, MPS2_MAX_PORTS, GFP_KERNEL); |
---|
501 | 541 | |
---|
502 | | - if (WARN_ON(id >= MPS2_MAX_PORTS)) |
---|
503 | | - return NULL; |
---|
| 542 | + if (id < 0) |
---|
| 543 | + return id; |
---|
504 | 544 | |
---|
505 | | - mps2_uart_ports[id].port.line = id; |
---|
506 | | - return &mps2_uart_ports[id]; |
---|
| 545 | + /* Only combined irq is presesnt */ |
---|
| 546 | + if (platform_irq_count(pdev) == 1) |
---|
| 547 | + mps_port->flags |= UART_PORT_COMBINED_IRQ; |
---|
| 548 | + |
---|
| 549 | + mps_port->port.line = id; |
---|
| 550 | + |
---|
| 551 | + return 0; |
---|
507 | 552 | } |
---|
508 | 553 | |
---|
509 | | -static int mps2_init_port(struct mps2_uart_port *mps_port, |
---|
510 | | - struct platform_device *pdev) |
---|
| 554 | +static int mps2_init_port(struct platform_device *pdev, |
---|
| 555 | + struct mps2_uart_port *mps_port) |
---|
511 | 556 | { |
---|
512 | 557 | struct resource *res; |
---|
513 | 558 | int ret; |
---|
.. | .. |
---|
519 | 564 | |
---|
520 | 565 | mps_port->port.mapbase = res->start; |
---|
521 | 566 | mps_port->port.mapsize = resource_size(res); |
---|
522 | | - |
---|
523 | | - mps_port->rx_irq = platform_get_irq(pdev, 0); |
---|
524 | | - mps_port->tx_irq = platform_get_irq(pdev, 1); |
---|
525 | | - mps_port->port.irq = platform_get_irq(pdev, 2); |
---|
526 | | - |
---|
527 | 567 | mps_port->port.iotype = UPIO_MEM; |
---|
528 | 568 | mps_port->port.flags = UPF_BOOT_AUTOCONF; |
---|
529 | 569 | mps_port->port.fifosize = 1; |
---|
.. | .. |
---|
542 | 582 | |
---|
543 | 583 | clk_disable_unprepare(mps_port->clk); |
---|
544 | 584 | |
---|
| 585 | + |
---|
| 586 | + if (mps_port->flags & UART_PORT_COMBINED_IRQ) { |
---|
| 587 | + mps_port->port.irq = platform_get_irq(pdev, 0); |
---|
| 588 | + } else { |
---|
| 589 | + mps_port->rx_irq = platform_get_irq(pdev, 0); |
---|
| 590 | + mps_port->tx_irq = platform_get_irq(pdev, 1); |
---|
| 591 | + mps_port->port.irq = platform_get_irq(pdev, 2); |
---|
| 592 | + } |
---|
| 593 | + |
---|
545 | 594 | return ret; |
---|
546 | 595 | } |
---|
547 | 596 | |
---|
.. | .. |
---|
550 | 599 | struct mps2_uart_port *mps_port; |
---|
551 | 600 | int ret; |
---|
552 | 601 | |
---|
553 | | - mps_port = mps2_of_get_port(pdev); |
---|
554 | | - if (!mps_port) |
---|
555 | | - return -ENODEV; |
---|
| 602 | + mps_port = devm_kzalloc(&pdev->dev, sizeof(struct mps2_uart_port), GFP_KERNEL); |
---|
556 | 603 | |
---|
557 | | - ret = mps2_init_port(mps_port, pdev); |
---|
| 604 | + if (!mps_port) |
---|
| 605 | + return -ENOMEM; |
---|
| 606 | + |
---|
| 607 | + ret = mps2_of_get_port(pdev, mps_port); |
---|
| 608 | + if (ret) |
---|
| 609 | + return ret; |
---|
| 610 | + |
---|
| 611 | + ret = mps2_init_port(pdev, mps_port); |
---|
558 | 612 | if (ret) |
---|
559 | 613 | return ret; |
---|
560 | 614 | |
---|