diff options
Diffstat (limited to 'drivers/tty/serial/sccnxp.c')
-rw-r--r-- | drivers/tty/serial/sccnxp.c | 171 |
1 files changed, 113 insertions, 58 deletions
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 418b495e3233..caccbe8fc1be 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c | |||
@@ -23,8 +23,9 @@ | |||
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/tty.h> | 24 | #include <linux/tty.h> |
25 | #include <linux/tty_flip.h> | 25 | #include <linux/tty_flip.h> |
26 | #include <linux/spinlock.h> | ||
26 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
27 | #include <linux/platform_data/sccnxp.h> | 28 | #include <linux/platform_data/serial-sccnxp.h> |
28 | 29 | ||
29 | #define SCCNXP_NAME "uart-sccnxp" | 30 | #define SCCNXP_NAME "uart-sccnxp" |
30 | #define SCCNXP_MAJOR 204 | 31 | #define SCCNXP_MAJOR 204 |
@@ -106,6 +107,7 @@ enum { | |||
106 | struct sccnxp_port { | 107 | struct sccnxp_port { |
107 | struct uart_driver uart; | 108 | struct uart_driver uart; |
108 | struct uart_port port[SCCNXP_MAX_UARTS]; | 109 | struct uart_port port[SCCNXP_MAX_UARTS]; |
110 | bool opened[SCCNXP_MAX_UARTS]; | ||
109 | 111 | ||
110 | const char *name; | 112 | const char *name; |
111 | int irq; | 113 | int irq; |
@@ -122,7 +124,10 @@ struct sccnxp_port { | |||
122 | struct console console; | 124 | struct console console; |
123 | #endif | 125 | #endif |
124 | 126 | ||
125 | struct mutex sccnxp_mutex; | 127 | spinlock_t lock; |
128 | |||
129 | bool poll; | ||
130 | struct timer_list timer; | ||
126 | 131 | ||
127 | struct sccnxp_pdata pdata; | 132 | struct sccnxp_pdata pdata; |
128 | }; | 133 | }; |
@@ -174,14 +179,12 @@ static int sccnxp_update_best_err(int a, int b, int *besterr) | |||
174 | return 1; | 179 | return 1; |
175 | } | 180 | } |
176 | 181 | ||
177 | struct baud_table { | 182 | static const struct { |
178 | u8 csr; | 183 | u8 csr; |
179 | u8 acr; | 184 | u8 acr; |
180 | u8 mr0; | 185 | u8 mr0; |
181 | int baud; | 186 | int baud; |
182 | }; | 187 | } baud_std[] = { |
183 | |||
184 | const struct baud_table baud_std[] = { | ||
185 | { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, }, | 188 | { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, }, |
186 | { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, }, | 189 | { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, }, |
187 | { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, }, | 190 | { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, }, |
@@ -285,10 +288,6 @@ static void sccnxp_handle_rx(struct uart_port *port) | |||
285 | { | 288 | { |
286 | u8 sr; | 289 | u8 sr; |
287 | unsigned int ch, flag; | 290 | unsigned int ch, flag; |
288 | struct tty_struct *tty = tty_port_tty_get(&port->state->port); | ||
289 | |||
290 | if (!tty) | ||
291 | return; | ||
292 | 291 | ||
293 | for (;;) { | 292 | for (;;) { |
294 | sr = sccnxp_port_read(port, SCCNXP_SR_REG); | 293 | sr = sccnxp_port_read(port, SCCNXP_SR_REG); |
@@ -304,14 +303,19 @@ static void sccnxp_handle_rx(struct uart_port *port) | |||
304 | if (unlikely(sr)) { | 303 | if (unlikely(sr)) { |
305 | if (sr & SR_BRK) { | 304 | if (sr & SR_BRK) { |
306 | port->icount.brk++; | 305 | port->icount.brk++; |
306 | sccnxp_port_write(port, SCCNXP_CR_REG, | ||
307 | CR_CMD_BREAK_RESET); | ||
307 | if (uart_handle_break(port)) | 308 | if (uart_handle_break(port)) |
308 | continue; | 309 | continue; |
309 | } else if (sr & SR_PE) | 310 | } else if (sr & SR_PE) |
310 | port->icount.parity++; | 311 | port->icount.parity++; |
311 | else if (sr & SR_FE) | 312 | else if (sr & SR_FE) |
312 | port->icount.frame++; | 313 | port->icount.frame++; |
313 | else if (sr & SR_OVR) | 314 | else if (sr & SR_OVR) { |
314 | port->icount.overrun++; | 315 | port->icount.overrun++; |
316 | sccnxp_port_write(port, SCCNXP_CR_REG, | ||
317 | CR_CMD_STATUS_RESET); | ||
318 | } | ||
315 | 319 | ||
316 | sr &= port->read_status_mask; | 320 | sr &= port->read_status_mask; |
317 | if (sr & SR_BRK) | 321 | if (sr & SR_BRK) |
@@ -333,9 +337,7 @@ static void sccnxp_handle_rx(struct uart_port *port) | |||
333 | uart_insert_char(port, sr, SR_OVR, ch, flag); | 337 | uart_insert_char(port, sr, SR_OVR, ch, flag); |
334 | } | 338 | } |
335 | 339 | ||
336 | tty_flip_buffer_push(tty); | 340 | tty_flip_buffer_push(&port->state->port); |
337 | |||
338 | tty_kref_put(tty); | ||
339 | } | 341 | } |
340 | 342 | ||
341 | static void sccnxp_handle_tx(struct uart_port *port) | 343 | static void sccnxp_handle_tx(struct uart_port *port) |
@@ -377,31 +379,48 @@ static void sccnxp_handle_tx(struct uart_port *port) | |||
377 | uart_write_wakeup(port); | 379 | uart_write_wakeup(port); |
378 | } | 380 | } |
379 | 381 | ||
380 | static irqreturn_t sccnxp_ist(int irq, void *dev_id) | 382 | static void sccnxp_handle_events(struct sccnxp_port *s) |
381 | { | 383 | { |
382 | int i; | 384 | int i; |
383 | u8 isr; | 385 | u8 isr; |
384 | struct sccnxp_port *s = (struct sccnxp_port *)dev_id; | ||
385 | |||
386 | mutex_lock(&s->sccnxp_mutex); | ||
387 | 386 | ||
388 | for (;;) { | 387 | do { |
389 | isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG); | 388 | isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG); |
390 | isr &= s->imr; | 389 | isr &= s->imr; |
391 | if (!isr) | 390 | if (!isr) |
392 | break; | 391 | break; |
393 | 392 | ||
394 | dev_dbg(s->port[0].dev, "IRQ status: 0x%02x\n", isr); | ||
395 | |||
396 | for (i = 0; i < s->uart.nr; i++) { | 393 | for (i = 0; i < s->uart.nr; i++) { |
397 | if (isr & ISR_RXRDY(i)) | 394 | if (s->opened[i] && (isr & ISR_RXRDY(i))) |
398 | sccnxp_handle_rx(&s->port[i]); | 395 | sccnxp_handle_rx(&s->port[i]); |
399 | if (isr & ISR_TXRDY(i)) | 396 | if (s->opened[i] && (isr & ISR_TXRDY(i))) |
400 | sccnxp_handle_tx(&s->port[i]); | 397 | sccnxp_handle_tx(&s->port[i]); |
401 | } | 398 | } |
402 | } | 399 | } while (1); |
400 | } | ||
401 | |||
402 | static void sccnxp_timer(unsigned long data) | ||
403 | { | ||
404 | struct sccnxp_port *s = (struct sccnxp_port *)data; | ||
405 | unsigned long flags; | ||
403 | 406 | ||
404 | mutex_unlock(&s->sccnxp_mutex); | 407 | spin_lock_irqsave(&s->lock, flags); |
408 | sccnxp_handle_events(s); | ||
409 | spin_unlock_irqrestore(&s->lock, flags); | ||
410 | |||
411 | if (!timer_pending(&s->timer)) | ||
412 | mod_timer(&s->timer, jiffies + | ||
413 | usecs_to_jiffies(s->pdata.poll_time_us)); | ||
414 | } | ||
415 | |||
416 | static irqreturn_t sccnxp_ist(int irq, void *dev_id) | ||
417 | { | ||
418 | struct sccnxp_port *s = (struct sccnxp_port *)dev_id; | ||
419 | unsigned long flags; | ||
420 | |||
421 | spin_lock_irqsave(&s->lock, flags); | ||
422 | sccnxp_handle_events(s); | ||
423 | spin_unlock_irqrestore(&s->lock, flags); | ||
405 | 424 | ||
406 | return IRQ_HANDLED; | 425 | return IRQ_HANDLED; |
407 | } | 426 | } |
@@ -409,8 +428,9 @@ static irqreturn_t sccnxp_ist(int irq, void *dev_id) | |||
409 | static void sccnxp_start_tx(struct uart_port *port) | 428 | static void sccnxp_start_tx(struct uart_port *port) |
410 | { | 429 | { |
411 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 430 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
431 | unsigned long flags; | ||
412 | 432 | ||
413 | mutex_lock(&s->sccnxp_mutex); | 433 | spin_lock_irqsave(&s->lock, flags); |
414 | 434 | ||
415 | /* Set direction to output */ | 435 | /* Set direction to output */ |
416 | if (s->flags & SCCNXP_HAVE_IO) | 436 | if (s->flags & SCCNXP_HAVE_IO) |
@@ -418,7 +438,7 @@ static void sccnxp_start_tx(struct uart_port *port) | |||
418 | 438 | ||
419 | sccnxp_enable_irq(port, IMR_TXRDY); | 439 | sccnxp_enable_irq(port, IMR_TXRDY); |
420 | 440 | ||
421 | mutex_unlock(&s->sccnxp_mutex); | 441 | spin_unlock_irqrestore(&s->lock, flags); |
422 | } | 442 | } |
423 | 443 | ||
424 | static void sccnxp_stop_tx(struct uart_port *port) | 444 | static void sccnxp_stop_tx(struct uart_port *port) |
@@ -429,20 +449,22 @@ static void sccnxp_stop_tx(struct uart_port *port) | |||
429 | static void sccnxp_stop_rx(struct uart_port *port) | 449 | static void sccnxp_stop_rx(struct uart_port *port) |
430 | { | 450 | { |
431 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 451 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
452 | unsigned long flags; | ||
432 | 453 | ||
433 | mutex_lock(&s->sccnxp_mutex); | 454 | spin_lock_irqsave(&s->lock, flags); |
434 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE); | 455 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE); |
435 | mutex_unlock(&s->sccnxp_mutex); | 456 | spin_unlock_irqrestore(&s->lock, flags); |
436 | } | 457 | } |
437 | 458 | ||
438 | static unsigned int sccnxp_tx_empty(struct uart_port *port) | 459 | static unsigned int sccnxp_tx_empty(struct uart_port *port) |
439 | { | 460 | { |
440 | u8 val; | 461 | u8 val; |
462 | unsigned long flags; | ||
441 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 463 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
442 | 464 | ||
443 | mutex_lock(&s->sccnxp_mutex); | 465 | spin_lock_irqsave(&s->lock, flags); |
444 | val = sccnxp_port_read(port, SCCNXP_SR_REG); | 466 | val = sccnxp_port_read(port, SCCNXP_SR_REG); |
445 | mutex_unlock(&s->sccnxp_mutex); | 467 | spin_unlock_irqrestore(&s->lock, flags); |
446 | 468 | ||
447 | return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; | 469 | return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; |
448 | } | 470 | } |
@@ -455,28 +477,30 @@ static void sccnxp_enable_ms(struct uart_port *port) | |||
455 | static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) | 477 | static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) |
456 | { | 478 | { |
457 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 479 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
480 | unsigned long flags; | ||
458 | 481 | ||
459 | if (!(s->flags & SCCNXP_HAVE_IO)) | 482 | if (!(s->flags & SCCNXP_HAVE_IO)) |
460 | return; | 483 | return; |
461 | 484 | ||
462 | mutex_lock(&s->sccnxp_mutex); | 485 | spin_lock_irqsave(&s->lock, flags); |
463 | 486 | ||
464 | sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR); | 487 | sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR); |
465 | sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS); | 488 | sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS); |
466 | 489 | ||
467 | mutex_unlock(&s->sccnxp_mutex); | 490 | spin_unlock_irqrestore(&s->lock, flags); |
468 | } | 491 | } |
469 | 492 | ||
470 | static unsigned int sccnxp_get_mctrl(struct uart_port *port) | 493 | static unsigned int sccnxp_get_mctrl(struct uart_port *port) |
471 | { | 494 | { |
472 | u8 bitmask, ipr; | 495 | u8 bitmask, ipr; |
496 | unsigned long flags; | ||
473 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 497 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
474 | unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; | 498 | unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; |
475 | 499 | ||
476 | if (!(s->flags & SCCNXP_HAVE_IO)) | 500 | if (!(s->flags & SCCNXP_HAVE_IO)) |
477 | return mctrl; | 501 | return mctrl; |
478 | 502 | ||
479 | mutex_lock(&s->sccnxp_mutex); | 503 | spin_lock_irqsave(&s->lock, flags); |
480 | 504 | ||
481 | ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG); | 505 | ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG); |
482 | 506 | ||
@@ -505,7 +529,7 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port) | |||
505 | mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0; | 529 | mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0; |
506 | } | 530 | } |
507 | 531 | ||
508 | mutex_unlock(&s->sccnxp_mutex); | 532 | spin_unlock_irqrestore(&s->lock, flags); |
509 | 533 | ||
510 | return mctrl; | 534 | return mctrl; |
511 | } | 535 | } |
@@ -513,21 +537,23 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port) | |||
513 | static void sccnxp_break_ctl(struct uart_port *port, int break_state) | 537 | static void sccnxp_break_ctl(struct uart_port *port, int break_state) |
514 | { | 538 | { |
515 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 539 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
540 | unsigned long flags; | ||
516 | 541 | ||
517 | mutex_lock(&s->sccnxp_mutex); | 542 | spin_lock_irqsave(&s->lock, flags); |
518 | sccnxp_port_write(port, SCCNXP_CR_REG, break_state ? | 543 | sccnxp_port_write(port, SCCNXP_CR_REG, break_state ? |
519 | CR_CMD_START_BREAK : CR_CMD_STOP_BREAK); | 544 | CR_CMD_START_BREAK : CR_CMD_STOP_BREAK); |
520 | mutex_unlock(&s->sccnxp_mutex); | 545 | spin_unlock_irqrestore(&s->lock, flags); |
521 | } | 546 | } |
522 | 547 | ||
523 | static void sccnxp_set_termios(struct uart_port *port, | 548 | static void sccnxp_set_termios(struct uart_port *port, |
524 | struct ktermios *termios, struct ktermios *old) | 549 | struct ktermios *termios, struct ktermios *old) |
525 | { | 550 | { |
526 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 551 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
552 | unsigned long flags; | ||
527 | u8 mr1, mr2; | 553 | u8 mr1, mr2; |
528 | int baud; | 554 | int baud; |
529 | 555 | ||
530 | mutex_lock(&s->sccnxp_mutex); | 556 | spin_lock_irqsave(&s->lock, flags); |
531 | 557 | ||
532 | /* Mask termios capabilities we don't support */ | 558 | /* Mask termios capabilities we don't support */ |
533 | termios->c_cflag &= ~CMSPAR; | 559 | termios->c_cflag &= ~CMSPAR; |
@@ -594,20 +620,22 @@ static void sccnxp_set_termios(struct uart_port *port, | |||
594 | /* Update timeout according to new baud rate */ | 620 | /* Update timeout according to new baud rate */ |
595 | uart_update_timeout(port, termios->c_cflag, baud); | 621 | uart_update_timeout(port, termios->c_cflag, baud); |
596 | 622 | ||
623 | /* Report actual baudrate back to core */ | ||
597 | if (tty_termios_baud_rate(termios)) | 624 | if (tty_termios_baud_rate(termios)) |
598 | tty_termios_encode_baud_rate(termios, baud, baud); | 625 | tty_termios_encode_baud_rate(termios, baud, baud); |
599 | 626 | ||
600 | /* Enable RX & TX */ | 627 | /* Enable RX & TX */ |
601 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); | 628 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); |
602 | 629 | ||
603 | mutex_unlock(&s->sccnxp_mutex); | 630 | spin_unlock_irqrestore(&s->lock, flags); |
604 | } | 631 | } |
605 | 632 | ||
606 | static int sccnxp_startup(struct uart_port *port) | 633 | static int sccnxp_startup(struct uart_port *port) |
607 | { | 634 | { |
608 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 635 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
636 | unsigned long flags; | ||
609 | 637 | ||
610 | mutex_lock(&s->sccnxp_mutex); | 638 | spin_lock_irqsave(&s->lock, flags); |
611 | 639 | ||
612 | if (s->flags & SCCNXP_HAVE_IO) { | 640 | if (s->flags & SCCNXP_HAVE_IO) { |
613 | /* Outputs are controlled manually */ | 641 | /* Outputs are controlled manually */ |
@@ -626,7 +654,9 @@ static int sccnxp_startup(struct uart_port *port) | |||
626 | /* Enable RX interrupt */ | 654 | /* Enable RX interrupt */ |
627 | sccnxp_enable_irq(port, IMR_RXRDY); | 655 | sccnxp_enable_irq(port, IMR_RXRDY); |
628 | 656 | ||
629 | mutex_unlock(&s->sccnxp_mutex); | 657 | s->opened[port->line] = 1; |
658 | |||
659 | spin_unlock_irqrestore(&s->lock, flags); | ||
630 | 660 | ||
631 | return 0; | 661 | return 0; |
632 | } | 662 | } |
@@ -634,8 +664,11 @@ static int sccnxp_startup(struct uart_port *port) | |||
634 | static void sccnxp_shutdown(struct uart_port *port) | 664 | static void sccnxp_shutdown(struct uart_port *port) |
635 | { | 665 | { |
636 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 666 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
667 | unsigned long flags; | ||
637 | 668 | ||
638 | mutex_lock(&s->sccnxp_mutex); | 669 | spin_lock_irqsave(&s->lock, flags); |
670 | |||
671 | s->opened[port->line] = 0; | ||
639 | 672 | ||
640 | /* Disable interrupts */ | 673 | /* Disable interrupts */ |
641 | sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY); | 674 | sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY); |
@@ -647,7 +680,7 @@ static void sccnxp_shutdown(struct uart_port *port) | |||
647 | if (s->flags & SCCNXP_HAVE_IO) | 680 | if (s->flags & SCCNXP_HAVE_IO) |
648 | sccnxp_set_bit(port, DIR_OP, 0); | 681 | sccnxp_set_bit(port, DIR_OP, 0); |
649 | 682 | ||
650 | mutex_unlock(&s->sccnxp_mutex); | 683 | spin_unlock_irqrestore(&s->lock, flags); |
651 | } | 684 | } |
652 | 685 | ||
653 | static const char *sccnxp_type(struct uart_port *port) | 686 | static const char *sccnxp_type(struct uart_port *port) |
@@ -721,10 +754,11 @@ static void sccnxp_console_write(struct console *co, const char *c, unsigned n) | |||
721 | { | 754 | { |
722 | struct sccnxp_port *s = (struct sccnxp_port *)co->data; | 755 | struct sccnxp_port *s = (struct sccnxp_port *)co->data; |
723 | struct uart_port *port = &s->port[co->index]; | 756 | struct uart_port *port = &s->port[co->index]; |
757 | unsigned long flags; | ||
724 | 758 | ||
725 | mutex_lock(&s->sccnxp_mutex); | 759 | spin_lock_irqsave(&s->lock, flags); |
726 | uart_console_write(port, c, n, sccnxp_console_putchar); | 760 | uart_console_write(port, c, n, sccnxp_console_putchar); |
727 | mutex_unlock(&s->sccnxp_mutex); | 761 | spin_unlock_irqrestore(&s->lock, flags); |
728 | } | 762 | } |
729 | 763 | ||
730 | static int sccnxp_console_setup(struct console *co, char *options) | 764 | static int sccnxp_console_setup(struct console *co, char *options) |
@@ -763,7 +797,7 @@ static int sccnxp_probe(struct platform_device *pdev) | |||
763 | } | 797 | } |
764 | platform_set_drvdata(pdev, s); | 798 | platform_set_drvdata(pdev, s); |
765 | 799 | ||
766 | mutex_init(&s->sccnxp_mutex); | 800 | spin_lock_init(&s->lock); |
767 | 801 | ||
768 | /* Individual chip settings */ | 802 | /* Individual chip settings */ |
769 | switch (chiptype) { | 803 | switch (chiptype) { |
@@ -860,11 +894,19 @@ static int sccnxp_probe(struct platform_device *pdev) | |||
860 | } else | 894 | } else |
861 | memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); | 895 | memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); |
862 | 896 | ||
863 | s->irq = platform_get_irq(pdev, 0); | 897 | if (s->pdata.poll_time_us) { |
864 | if (s->irq <= 0) { | 898 | dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", |
865 | dev_err(&pdev->dev, "Missing irq resource data\n"); | 899 | s->pdata.poll_time_us); |
866 | ret = -ENXIO; | 900 | s->poll = 1; |
867 | goto err_out; | 901 | } |
902 | |||
903 | if (!s->poll) { | ||
904 | s->irq = platform_get_irq(pdev, 0); | ||
905 | if (s->irq < 0) { | ||
906 | dev_err(&pdev->dev, "Missing irq resource data\n"); | ||
907 | ret = -ENXIO; | ||
908 | goto err_out; | ||
909 | } | ||
868 | } | 910 | } |
869 | 911 | ||
870 | /* Check input frequency */ | 912 | /* Check input frequency */ |
@@ -929,13 +971,23 @@ static int sccnxp_probe(struct platform_device *pdev) | |||
929 | if (s->pdata.init) | 971 | if (s->pdata.init) |
930 | s->pdata.init(); | 972 | s->pdata.init(); |
931 | 973 | ||
932 | ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, sccnxp_ist, | 974 | if (!s->poll) { |
933 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 975 | ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, |
934 | dev_name(&pdev->dev), s); | 976 | sccnxp_ist, |
935 | if (!ret) | 977 | IRQF_TRIGGER_FALLING | |
978 | IRQF_ONESHOT, | ||
979 | dev_name(&pdev->dev), s); | ||
980 | if (!ret) | ||
981 | return 0; | ||
982 | |||
983 | dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); | ||
984 | } else { | ||
985 | init_timer(&s->timer); | ||
986 | setup_timer(&s->timer, sccnxp_timer, (unsigned long)s); | ||
987 | mod_timer(&s->timer, jiffies + | ||
988 | usecs_to_jiffies(s->pdata.poll_time_us)); | ||
936 | return 0; | 989 | return 0; |
937 | 990 | } | |
938 | dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); | ||
939 | 991 | ||
940 | err_out: | 992 | err_out: |
941 | platform_set_drvdata(pdev, NULL); | 993 | platform_set_drvdata(pdev, NULL); |
@@ -948,7 +1000,10 @@ static int sccnxp_remove(struct platform_device *pdev) | |||
948 | int i; | 1000 | int i; |
949 | struct sccnxp_port *s = platform_get_drvdata(pdev); | 1001 | struct sccnxp_port *s = platform_get_drvdata(pdev); |
950 | 1002 | ||
951 | devm_free_irq(&pdev->dev, s->irq, s); | 1003 | if (!s->poll) |
1004 | devm_free_irq(&pdev->dev, s->irq, s); | ||
1005 | else | ||
1006 | del_timer_sync(&s->timer); | ||
952 | 1007 | ||
953 | for (i = 0; i < s->uart.nr; i++) | 1008 | for (i = 0; i < s->uart.nr; i++) |
954 | uart_remove_one_port(&s->uart, &s->port[i]); | 1009 | uart_remove_one_port(&s->uart, &s->port[i]); |