static int s3c_serial_resume(struct platform_device *dev) { struct uart_port *port = s3c_dev_to_port(&dev->dev); struct s3c_uart_port *ourport = to_ourport(port); if (port) { clk_enable(ourport->clk); s3c_serial_resetport(port, s3c_port_to_cfg(port)); clk_disable(ourport->clk); uart_resume_port(&s3c_uart_drv, port); } return 0; }
static int s3c_serial_resume(struct platform_device *dev) { struct uart_port *port = s3c_dev_to_port(&dev->dev); struct s3c_uart_port *ourport = to_ourport(port); unsigned int gpadata = 0; if (port) { clk_enable(ourport->clk); s3c_serial_resetport(port, s3c_port_to_cfg(port)); clk_disable(ourport->clk); s3c6410_pm_do_restore(uart_save + port->line * SAVE_UART_PORT, SAVE_UART_PORT); uart_resume_port(&s3c_uart_drv, port); } if (port->line == 0) { gpadata = __raw_readl(S3C64XX_GPADAT); gpadata &= ~(1<<3); __raw_writel(gpadata, S3C64XX_GPADAT); } else if(port->line == 1) { s3c_gpio_cfgpin(S3C64XX_GPA(7), S3C_GPIO_SFN(1)); gpadata = __raw_readl(S3C64XX_GPADAT); gpadata &= ~(1<<7); __raw_writel(gpadata, S3C64XX_GPADAT); s3c_gpio_setpull(S3C64XX_GPA(7), S3C_GPIO_PULL_NONE); s3c_gpio_cfgpin(S3C64XX_GPA(7), S3C_GPIO_SFN(2)); } return 0; }
static void s3c_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct s3c_uartcfg *cfg = s3c_port_to_cfg(port); struct s3c_uart_port *ourport = to_ourport(port); struct s3c_uart_clksrc *clksrc = NULL; struct clk *clk = NULL; unsigned long flags; unsigned int baud, ubrdiv, udivslot; unsigned int ulcon; unsigned int umcon; /* * We don't support modem control lines. */ termios->c_cflag &= ~(HUPCL | CMSPAR); termios->c_cflag |= CLOCAL; /* * Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, 4000000); if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { ubrdiv = port->custom_divisor; udivslot = 0; } else ubrdiv = s3c_serial_getclk(port, &clksrc, &clk, baud, &udivslot); /* check to see if we need to change clock source */ if (ourport->clksrc != clksrc || ourport->baudclk != clk) { s3c_serial_setsource(port, clksrc); if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { clk_disable(ourport->baudclk); ourport->baudclk = NULL; } clk_enable(clk); ourport->clksrc = clksrc; ourport->baudclk = clk; ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; } switch (termios->c_cflag & CSIZE) { case CS5: dbg("config: 5bits/char\n"); ulcon = S3C_LCON_CS5; break; case CS6: dbg("config: 6bits/char\n"); ulcon = S3C_LCON_CS6; break; case CS7: dbg("config: 7bits/char\n"); ulcon = S3C_LCON_CS7; break; case CS8: default: dbg("config: 8bits/char\n"); ulcon = S3C_LCON_CS8; break; } /* preserve original lcon IR settings */ ulcon |= (cfg->ulcon & S3C_LCON_IRM); if (termios->c_cflag & CSTOPB) ulcon |= S3C_LCON_STOPB; umcon = (termios->c_cflag & CRTSCTS) ? S3C_UMCOM_AFC : 0; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) ulcon |= S3C_LCON_PODD; else ulcon |= S3C_LCON_PEVEN; } else { ulcon |= S3C_LCON_PNONE; } spin_lock_irqsave(&port->lock, flags); dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot); wr_regl(port, S3C_ULCON, ulcon); wr_regl(port, S3C_UBRDIV, ubrdiv); wr_regl(port, S3C_UDIVSLOT, udivslot_table[udivslot]); wr_regl(port, S3C_UMCON, umcon); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); /* * Which character status flags are we interested in? */ port->read_status_mask = S3C_UERSTAT_OVERRUN; if (termios->c_iflag & INPCK) port->read_status_mask |= S3C_UERSTAT_FRAME | S3C_UERSTAT_PARITY; /* * Which character status flags should we ignore? */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C_UERSTAT_OVERRUN; if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C_UERSTAT_FRAME; /* * Ignore all characters if CREAD is not set. */ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= RXSTAT_DUMMY_READ; spin_unlock_irqrestore(&port->lock, flags); }
static unsigned int s3c_serial_getclk(struct uart_port *port, struct s3c_uart_clksrc **clksrc, struct clk **clk, unsigned int baud, unsigned int *udivslot) { struct s3c_uartcfg *cfg = s3c_port_to_cfg(port); struct s3c_uart_clksrc *clkp; struct baud_calc res[MAX_CLKS]; struct baud_calc *resptr, *best, *sptr; struct clk *uclk1; int i; clkp = cfg->clocks; best = NULL; if (cfg->clocks_size < 2) { if (cfg->clocks_size == 0) clkp = &tmp_clksrc; /* check to see if we're sourcing fclk, and if so we're * going to have to update the clock source */ if (strcmp(clkp->name, "fclk") == 0) { struct s3c_uart_clksrc src; s3c_serial_getsource(port, &src); /* check that the port already using fclk, and if * not, then re-select fclk */ if (strcmp(src.name, clkp->name) == 0) { s3c_serial_setsource(port, clkp); s3c_serial_getsource(port, &src); } clkp->divisor = src.divisor; } if (strcmp(clkp->name, "uclk1") == 0) { uclk1 = clk_get(NULL, clkp->name); clk_set_parent(uclk1, clk_get(NULL, "dout_mpll")); clk_set_rate(uclk1, 133000000); clk_put(uclk1); } s3c_serial_calcbaud(res, port, clkp, baud); best = res; resptr = best + 1; } else { resptr = res; for (i = 0; i < cfg->clocks_size; i++, clkp++) { if (s3c_serial_calcbaud(resptr, port, clkp, baud)) resptr++; } } /* ok, we now need to select the best clock we found */ if (!best) { unsigned int deviation = (1<<30)|((1<<30)-1); int calc_deviation; for (sptr = res; sptr < resptr; sptr++) { calc_deviation = baud - sptr->calc; if (calc_deviation < 0) calc_deviation = -calc_deviation; if (calc_deviation < deviation) { best = sptr; deviation = calc_deviation; } } } /* store results to pass back */ *clksrc = best->clksrc; *clk = best->src; *udivslot = best->udivslot; return best->ubrdiv; }
static unsigned int s3c_serial_getclk(struct uart_port *port, struct s3c24xx_uart_clksrc **clksrc, struct clk **clk, unsigned int baud, unsigned int *slot) { struct s3c2410_uartcfg *cfg = s3c_port_to_cfg(port); struct s3c24xx_uart_clksrc *clkp; struct baud_calc res[MAX_CLKS]; struct baud_calc *resptr, *best, *sptr; int i; clkp = cfg->clocks; best = NULL; if (cfg->clocks_size < 2) { if (cfg->clocks_size == 0) clkp = &tmp_clksrc; /* check to see if we're sourcing fclk, and if so we're * going to have to update the clock source */ if (strcmp(clkp->name, "fclk") == 0) { struct s3c24xx_uart_clksrc src; s3c_serial_getsource(port, &src); /* check that the port already using fclk, and if * not, then re-select fclk */ if (strcmp(src.name, clkp->name) == 0) { s3c_serial_setsource(port, clkp); s3c_serial_getsource(port, &src); } clkp->divisor = src.divisor; } s3c_serial_calcbaud(res, port, clkp, baud); best = res; resptr = best + 1; } else { resptr = res; for (i = 0; i < cfg->clocks_size; i++, clkp++) { if (s3c_serial_calcbaud(resptr, port, clkp, baud)) resptr++; } } /* ok, we now need to select the best clock we found */ if (best==NULL) { unsigned int deviation = (1<<30)|((1<<30)-1); int calc_deviation; best = sptr = res; for (sptr = res; sptr < resptr; sptr++) { printk(KERN_DEBUG "found clk %p (%s) quot %d, calc %d\n", sptr->clksrc, sptr->clksrc->name, sptr->quot, sptr->calc); calc_deviation = baud - sptr->calc; if (calc_deviation < 0) calc_deviation = -calc_deviation; if (calc_deviation < deviation) { best = sptr; deviation = calc_deviation; } } printk(KERN_DEBUG "The best clksrc among candidate clksrc: %p(%s) (deviation: %d bps)\n", best, best->clksrc->name, deviation); } printk(KERN_DEBUG "Selected clock is %p (%s) quot %d, calc %d\n", best->clksrc, best->clksrc->name, best->quot, best->calc); /* store results to pass back */ *clksrc = best->clksrc; *clk = best->src; *slot = best->slot; return best->quot; }