📄 s3c2410.c.txt
字号:
723 best = sptr;
724 deviation = calc_deviation;
725 }
726 }
727
728 printk(KERN_DEBUG "best %p (deviation %d)\n", best, deviation);
729 }
730
731 printk(KERN_DEBUG "selected clock %p (%s) quot %d, calc %d\n",
732 best->clksrc, best->clksrc->name, best->quot, best->calc);
733
734 /* store results to pass back */
735
736 *clksrc = best->clksrc;
737 *clk = best->src;
738
739 return best->quot;
740 }
741
742 static void s3c24xx_serial_set_termios(struct uart_port *port,
743 struct termios *termios,
744 struct termios *old)
745 {
746 struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
747 struct s3c24xx_uart_port *ourport = to_ourport(port);
748 struct s3c24xx_uart_clksrc *clksrc = NULL;
749 struct clk *clk = NULL;
750 unsigned long flags;
751 unsigned int baud, quot;
752 unsigned int ulcon;
753 unsigned int umcon;
754
755 /*
756 * We don't support modem control lines.
757 */
758 termios->c_cflag &= ~(HUPCL | CMSPAR);
759 termios->c_cflag |= CLOCAL;
760
761 /*
762 * Ask the core to calculate the divisor for us.
763 */
764
765 baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
766
767 if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
768 quot = port->custom_divisor;
769 else
770 quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
771
772 /* check to see if we need to change clock source */
773
774 if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
775 s3c24xx_serial_setsource(port, clksrc);
776
777 if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
778 clk_disable(ourport->baudclk);
779 ourport->baudclk = NULL;
780 }
781
782 clk_enable(clk);
783
784 ourport->clksrc = clksrc;
785 ourport->baudclk = clk;
786 }
787
788 switch (termios->c_cflag & CSIZE) {
789 case CS5:
790 dbg("config: 5bits/char\n");
791 ulcon = S3C2410_LCON_CS5;
792 break;
793 case CS6:
794 dbg("config: 6bits/char\n");
795 ulcon = S3C2410_LCON_CS6;
796 break;
797 case CS7:
798 dbg("config: 7bits/char\n");
799 ulcon = S3C2410_LCON_CS7;
800 break;
801 case CS8:
802 default:
803 dbg("config: 8bits/char\n");
804 ulcon = S3C2410_LCON_CS8;
805 break;
806 }
807
808 /* preserve original lcon IR settings */
809 ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
810
811 if (termios->c_cflag & CSTOPB)
812 ulcon |= S3C2410_LCON_STOPB;
813
814 umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
815
816 if (termios->c_cflag & PARENB) {
817 if (termios->c_cflag & PARODD)
818 ulcon |= S3C2410_LCON_PODD;
819 else
820 ulcon |= S3C2410_LCON_PEVEN;
821 } else {
822 ulcon |= S3C2410_LCON_PNONE;
823 }
824
825 spin_lock_irqsave(&port->lock, flags);
826
827 dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);
828
829 wr_regl(port, S3C2410_ULCON, ulcon);
830 wr_regl(port, S3C2410_UBRDIV, quot);
831 wr_regl(port, S3C2410_UMCON, umcon);
832
833 dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
834 rd_regl(port, S3C2410_ULCON),
835 rd_regl(port, S3C2410_UCON),
836 rd_regl(port, S3C2410_UFCON));
837
838 /*
839 * Update the per-port timeout.
840 */
841 uart_update_timeout(port, termios->c_cflag, baud);
842
843 /*
844 * Which character status flags are we interested in?
845 */
846 port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
847 if (termios->c_iflag & INPCK)
848 port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
849
850 /*
851 * Which character status flags should we ignore?
852 */
853 port->ignore_status_mask = 0;
854 if (termios->c_iflag & IGNPAR)
855 port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
856 if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
857 port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
858
859 /*
860 * Ignore all characters if CREAD is not set.
861 */
862 if ((termios->c_cflag & CREAD) == 0)
863 port->ignore_status_mask |= RXSTAT_DUMMY_READ;
864
865 spin_unlock_irqrestore(&port->lock, flags);
866 }
867
868 static const char *s3c24xx_serial_type(struct uart_port *port)
869 {
870 switch (port->type) {
871 case PORT_S3C2410:
872 return "S3C2410";
873 case PORT_S3C2440:
874 return "S3C2440";
875 default:
876 return NULL;
877 }
878 }
879
880 #define MAP_SIZE (0x100)
881
882 static void s3c24xx_serial_release_port(struct uart_port *port)
883 {
884 release_mem_region(port->mapbase, MAP_SIZE);
885 }
886
887 static int s3c24xx_serial_request_port(struct uart_port *port)
888 {
889 const char *name = s3c24xx_serial_portname(port);
890 return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
891 }
892
893 static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
894 {
895 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
896
897 if (flags & UART_CONFIG_TYPE &&
898 s3c24xx_serial_request_port(port) == 0)
899 port->type = info->type;
900 }
901
902 /*
903 * verify the new serial_struct (for TIOCSSERIAL).
904 */
905 static int
906 s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
907 {
908 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
909
910 if (ser->type != PORT_UNKNOWN && ser->type != info->type)
911 return -EINVAL;
912
913 return 0;
914 }
915
916
917 #ifdef CONFIG_SERIAL_S3C2410_CONSOLE
918
919 static struct console s3c24xx_serial_console;
920
921 #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
922 #else
923 #define S3C24XX_SERIAL_CONSOLE NULL
924 #endif
925
926 static struct uart_ops s3c24xx_serial_ops = {
927 .pm = s3c24xx_serial_pm,
928 .tx_empty = s3c24xx_serial_tx_empty,
929 .get_mctrl = s3c24xx_serial_get_mctrl,
930 .set_mctrl = s3c24xx_serial_set_mctrl,
931 .stop_tx = s3c24xx_serial_stop_tx,
932 .start_tx = s3c24xx_serial_start_tx,
933 .stop_rx = s3c24xx_serial_stop_rx,
934 .enable_ms = s3c24xx_serial_enable_ms,
935 .break_ctl = s3c24xx_serial_break_ctl,
936 .startup = s3c24xx_serial_startup,
937 .shutdown = s3c24xx_serial_shutdown,
938 .set_termios = s3c24xx_serial_set_termios,
939 .type = s3c24xx_serial_type,
940 .release_port = s3c24xx_serial_release_port,
941 .request_port = s3c24xx_serial_request_port,
942 .config_port = s3c24xx_serial_config_port,
943 .verify_port = s3c24xx_serial_verify_port,
944 };
945
946
947 static struct uart_driver s3c24xx_uart_drv = {
948 .owner = THIS_MODULE,
949 .dev_name = "s3c2410_serial",
950 .nr = 3,
951 .cons = S3C24XX_SERIAL_CONSOLE,
952 .driver_name = S3C24XX_SERIAL_NAME,
953 .devfs_name = S3C24XX_SERIAL_DEVFS,
954 .major = S3C24XX_SERIAL_MAJOR,
955 .minor = S3C24XX_SERIAL_MINOR,
956 };
957
958 static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
959 [0] = {
960 .port = {
961 .lock = SPIN_LOCK_UNLOCKED,
962 .iotype = UPIO_MEM,
963 .irq = IRQ_S3CUART_RX0,
964 .uartclk = 0,
965 .fifosize = 16,
966 .ops = &s3c24xx_serial_ops,
967 .flags = UPF_BOOT_AUTOCONF,
968 .line = 0,
969 }
970 },
971 [1] = {
972 .port = {
973 .lock = SPIN_LOCK_UNLOCKED,
974 .iotype = UPIO_MEM,
975 .irq = IRQ_S3CUART_RX1,
976 .uartclk = 0,
977 .fifosize = 16,
978 .ops = &s3c24xx_serial_ops,
979 .flags = UPF_BOOT_AUTOCONF,
980 .line = 1,
981 }
982 },
983 #if NR_PORTS > 2
984
985 [2] = {
986 .port = {
987 .lock = SPIN_LOCK_UNLOCKED,
988 .iotype = UPIO_MEM,
989 .irq = IRQ_S3CUART_RX2,
990 .uartclk = 0,
991 .fifosize = 16,
992 .ops = &s3c24xx_serial_ops,
993 .flags = UPF_BOOT_AUTOCONF,
994 .line = 2,
995 }
996 }
997 #endif
998 };
999
1000 /* s3c24xx_serial_resetport
1001 *
1002 * wrapper to call the specific reset for this port (reset the fifos
1003 * and the settings)
1004 */
1005
1006 static inline int s3c24xx_serial_resetport(struct uart_port * port,
1007 struct s3c2410_uartcfg *cfg)
1008 {
1009 struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
1010
1011 return (info->reset_port)(port, cfg);
1012 }
1013
1014 /* s3c24xx_serial_init_port
1015 *
1016 * initialise a single serial port from the platform device given
1017 */
1018
1019 static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
1020 struct s3c24xx_uart_info *info,
1021 struct platform_device *platdev)
1022 {
1023 struct uart_port *port = &ourport->port;
1024 struct s3c2410_uartcfg *cfg;
1025 struct resource *res;
1026
1027 dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
1028
1029 if (platdev == NULL)
1030 return -ENODEV;
1031
1032 cfg = s3c24xx_dev_to_cfg(&platdev->dev);
1033
1034 if (port->mapbase != 0)
1035 return 0;
1036
1037 if (cfg->hwport > 3)
1038 return -EINVAL;
1039
1040 /* setup info for port */
1041 port->dev = &platdev->dev;
1042 ourport->info = info;
1043
1044 /* copy the info in from provided structure */
1045 ourport->port.fifosize = info->fifosize;
1046
1047 dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
1048
1049 port->uartclk = 1;
1050
1051 if (cfg->uart_flags & UPF_CONS_FLOW) {
1052 dbg("s3c24xx_serial_init_port: enabling flow control\n");
1053 port->flags |= UPF_CONS_FLOW;
1054 }
1055
1056 /* sort our the physical and virtual addresses for each UART */
1057
1058 res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
1059 if (res == NULL) {
1060 printk(KERN_ERR "failed to find memory resource for uart\n");
1061 return -EINVAL;
1062 }
1063
1064 dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
1065
1066 port->mapbase = res->start;
1067 port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
1068 port->irq = platform_get_irq(platdev, 0);
1069 if (port->irq < 0)
1070 port->irq = 0;
1071
1072 ourport->clk = clk_get(&platdev->dev, "uart");
1073
1074 dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n",
1075 port->mapbase, port->membase, port->irq, port->uartclk);
1076
1077 /* reset the fifos (and setup the uart) */
1078 s3c24xx_serial_resetport(port, cfg);
1079 return 0;
1080 }
1081
1082 /* Device driver serial port probe */
1083
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -