📄 s3c2410.c.txt
字号:
362 if (uerstat & S3C2410_UERSTAT_BREAK) {
363 dbg("break!\n");
364 port->icount.brk++;
365 if (uart_handle_break(port))
366 goto ignore_char;
367 }
368
369 if (uerstat & S3C2410_UERSTAT_FRAME)
370 port->icount.frame++;
371 if (uerstat & S3C2410_UERSTAT_OVERRUN)
372 port->icount.overrun++;
373
374 uerstat &= port->read_status_mask;
375
376 if (uerstat & S3C2410_UERSTAT_BREAK)
377 flag = TTY_BREAK;
378 else if (uerstat & S3C2410_UERSTAT_PARITY)
379 flag = TTY_PARITY;
380 else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
381 flag = TTY_FRAME;
382 }
383
384 if (uart_handle_sysrq_char(port, ch, regs))
385 goto ignore_char;
386
387 uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
388
389 ignore_char:
390 continue;
391 }
392 tty_flip_buffer_push(tty);
393
394 out:
395 return IRQ_HANDLED;
396 }
397
398 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *regs)
399 {
400 struct s3c24xx_uart_port *ourport = id;
401 struct uart_port *port = &ourport->port;
402 struct circ_buf *xmit = &port->info->xmit;
403 int count = 256;
404
405 if (port->x_char) {
406 wr_regb(port, S3C2410_UTXH, port->x_char);
407 port->icount.tx++;
408 port->x_char = 0;
409 goto out;
410 }
411
412 /* if there isnt anything more to transmit, or the uart is now
413 * stopped, disable the uart and exit
414 */
415
416 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
417 s3c24xx_serial_stop_tx(port);
418 goto out;
419 }
420
421 /* try and drain the buffer... */
422
423 while (!uart_circ_empty(xmit) && count-- > 0) {
424 if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
425 break;
426
427 wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
428 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
429 port->icount.tx++;
430 }
431
432 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
433 uart_write_wakeup(port);
434
435 if (uart_circ_empty(xmit))
436 s3c24xx_serial_stop_tx(port);
437
438 out:
439 return IRQ_HANDLED;
440 }
441
442 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
443 {
444 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
445 unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
446 unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
447
448 if (ufcon & S3C2410_UFCON_FIFOMODE) {
449 if ((ufstat & info->tx_fifomask) != 0 ||
450 (ufstat & info->tx_fifofull))
451 return 0;
452
453 return 1;
454 }
455
456 return s3c24xx_serial_txempty_nofifo(port);
457 }
458
459 /* no modem control lines */
460 static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
461 {
462 unsigned int umstat = rd_regb(port,S3C2410_UMSTAT);
463
464 if (umstat & S3C2410_UMSTAT_CTS)
465 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
466 else
467 return TIOCM_CAR | TIOCM_DSR;
468 }
469
470 static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
471 {
472 /* todo - possibly remove AFC and do manual CTS */
473 }
474
475 static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
476 {
477 unsigned long flags;
478 unsigned int ucon;
479
480 spin_lock_irqsave(&port->lock, flags);
481
482 ucon = rd_regl(port, S3C2410_UCON);
483
484 if (break_state)
485 ucon |= S3C2410_UCON_SBREAK;
486 else
487 ucon &= ~S3C2410_UCON_SBREAK;
488
489 wr_regl(port, S3C2410_UCON, ucon);
490
491 spin_unlock_irqrestore(&port->lock, flags);
492 }
493
494 static void s3c24xx_serial_shutdown(struct uart_port *port)
495 {
496 struct s3c24xx_uart_port *ourport = to_ourport(port);
497
498 if (ourport->tx_claimed) {
499 free_irq(TX_IRQ(port), ourport);
500 tx_enabled(port) = 0;
501 ourport->tx_claimed = 0;
502 }
503
504 if (ourport->rx_claimed) {
505 free_irq(RX_IRQ(port), ourport);
506 ourport->rx_claimed = 0;
507 rx_enabled(port) = 0;
508 }
509 }
510
511
512 static int s3c24xx_serial_startup(struct uart_port *port)
513 {
514 struct s3c24xx_uart_port *ourport = to_ourport(port);
515 int ret;
516
517 dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
518 port->mapbase, port->membase);
519
520 rx_enabled(port) = 1;
521
522 ret = request_irq(RX_IRQ(port),
523 s3c24xx_serial_rx_chars, 0,
524 s3c24xx_serial_portname(port), ourport);
525
526 if (ret != 0) {
527 printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));
528 return ret;
529 }
530
531 ourport->rx_claimed = 1;
532
533 dbg("requesting tx irq...\n");
534
535 tx_enabled(port) = 1;
536
537 ret = request_irq(TX_IRQ(port),
538 s3c24xx_serial_tx_chars, 0,
539 s3c24xx_serial_portname(port), ourport);
540
541 if (ret) {
542 printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));
543 goto err;
544 }
545
546 ourport->tx_claimed = 1;
547
548 dbg("s3c24xx_serial_startup ok\n");
549
550 /* the port reset code should have done the correct
551 * register setup for the port controls */
552
553 return ret;
554
555 err:
556 s3c24xx_serial_shutdown(port);
557 return ret;
558 }
559
560 /* power power management control */
561
562 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
563 unsigned int old)
564 {
565 struct s3c24xx_uart_port *ourport = to_ourport(port);
566
567 switch (level) {
568 case 3:
569 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
570 clk_disable(ourport->baudclk);
571
572 clk_disable(ourport->clk);
573 break;
574
575 case 0:
576 clk_enable(ourport->clk);
577
578 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
579 clk_enable(ourport->baudclk);
580
581 break;
582 default:
583 printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
584 }
585 }
586
587 /* baud rate calculation
588 *
589 * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
590 * of different sources, including the peripheral clock ("pclk") and an
591 * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
592 * with a programmable extra divisor.
593 *
594 * The following code goes through the clock sources, and calculates the
595 * baud clocks (and the resultant actual baud rates) and then tries to
596 * pick the closest one and select that.
597 *
598 */
599
600
601 #define MAX_CLKS (8)
602
603 static struct s3c24xx_uart_clksrc tmp_clksrc = {
604 .name = "pclk",
605 .min_baud = 0,
606 .max_baud = 0,
607 .divisor = 1,
608 };
609
610 static inline int
611 s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
612 {
613 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
614
615 return (info->get_clksrc)(port, c);
616 }
617
618 static inline int
619 s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
620 {
621 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
622
623 return (info->set_clksrc)(port, c);
624 }
625
626 struct baud_calc {
627 struct s3c24xx_uart_clksrc *clksrc;
628 unsigned int calc;
629 unsigned int quot;
630 struct clk *src;
631 };
632
633 static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
634 struct uart_port *port,
635 struct s3c24xx_uart_clksrc *clksrc,
636 unsigned int baud)
637 {
638 unsigned long rate;
639
640 calc->src = clk_get(port->dev, clksrc->name);
641 if (calc->src == NULL || IS_ERR(calc->src))
642 return 0;
643
644 rate = clk_get_rate(calc->src);
645 rate /= clksrc->divisor;
646
647 calc->clksrc = clksrc;
648 calc->quot = (rate + (8 * baud)) / (16 * baud);
649 calc->calc = (rate / (calc->quot * 16));
650
651 calc->quot--;
652 return 1;
653 }
654
655 static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
656 struct s3c24xx_uart_clksrc **clksrc,
657 struct clk **clk,
658 unsigned int baud)
659 {
660 struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
661 struct s3c24xx_uart_clksrc *clkp;
662 struct baud_calc res[MAX_CLKS];
663 struct baud_calc *resptr, *best, *sptr;
664 int i;
665
666 clkp = cfg->clocks;
667 best = NULL;
668
669 if (cfg->clocks_size < 2) {
670 if (cfg->clocks_size == 0)
671 clkp = &tmp_clksrc;
672
673 /* check to see if we're sourcing fclk, and if so we're
674 * going to have to update the clock source
675 */
676
677 if (strcmp(clkp->name, "fclk") == 0) {
678 struct s3c24xx_uart_clksrc src;
679
680 s3c24xx_serial_getsource(port, &src);
681
682 /* check that the port already using fclk, and if
683 * not, then re-select fclk
684 */
685
686 if (strcmp(src.name, clkp->name) == 0) {
687 s3c24xx_serial_setsource(port, clkp);
688 s3c24xx_serial_getsource(port, &src);
689 }
690
691 clkp->divisor = src.divisor;
692 }
693
694 s3c24xx_serial_calcbaud(res, port, clkp, baud);
695 best = res;
696 resptr = best + 1;
697 } else {
698 resptr = res;
699
700 for (i = 0; i < cfg->clocks_size; i++, clkp++) {
701 if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
702 resptr++;
703 }
704 }
705
706 /* ok, we now need to select the best clock we found */
707
708 if (!best) {
709 unsigned int deviation = (1<<30)|((1<<30)-1);
710 int calc_deviation;
711
712 for (sptr = res; sptr < resptr; sptr++) {
713 printk(KERN_DEBUG
714 "found clk %p (%s) quot %d, calc %d\n",
715 sptr->clksrc, sptr->clksrc->name,
716 sptr->quot, sptr->calc);
717
718 calc_deviation = baud - sptr->calc;
719 if (calc_deviation < 0)
720 calc_deviation = -calc_deviation;
721
722 if (calc_deviation < deviation) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -