static void s3c24xx_serial_wake_peer(struct uart_port *port) { struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); if (cfg->wake_peer) cfg->wake_peer(port); }
static int s3c24xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); int ret; dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", port->mapbase, port->membase); /* runstate should be 1 before request_irq is called */ if (cfg->set_runstate) cfg->set_runstate(1); rx_enabled(port) = 1; ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, s3c24xx_serial_portname(port), ourport); if (ret != 0) { printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq); goto err; } ourport->rx_claimed = 1; dbg("requesting tx irq...\n"); tx_enabled(port) = 1; ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, s3c24xx_serial_portname(port), ourport); if (ret) { printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq); goto err; } ourport->tx_claimed = 1; dbg("s3c24xx_serial_startup ok\n"); /* the port reset code should have done the correct * register setup for the port controls */ return ret; err: s3c24xx_serial_shutdown(port); return ret; }
static int s3c24xx_serial_resume(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); struct s3c24xx_uart_port *ourport = to_ourport(port); if (port) { clk_enable(ourport->clk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); clk_disable(ourport->clk); uart_resume_port(&s3c24xx_uart_drv, port); } return 0; }
int s3c24xx_serial_resume(struct device *dev, u32 level) { struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); if (port && level == RESUME_ENABLE) { clk_enable(ourport->clk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); clk_disable(ourport->clk); uart_resume_port(&s3c24xx_uart_drv, port); } return 0; }
static int s3c24xx_serial_resume(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); struct s3c24xx_uart_port *ourport = to_ourport(port); if (port) { clk_enable(ourport->clk); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); clk_disable(ourport->clk); s3c_pm_do_restore(uart_save + port->line * SAVE_UART_PORT, SAVE_UART_PORT); uart_resume_port(&s3c24xx_uart_drv, port); } return 0; }
static void s3c24xx_serial_shutdown(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); if (ourport->tx_claimed) { disable_irq(ourport->tx_irq); free_irq(ourport->tx_irq, ourport); tx_enabled(port) = 0; ourport->tx_claimed = 0; } if (ourport->rx_claimed) { disable_irq(ourport->rx_irq); free_irq(ourport->rx_irq, ourport); ourport->rx_claimed = 0; rx_enabled(port) = 0; } if (cfg->set_runstate) cfg->set_runstate(0); }
static void s3c24xx_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_clksrc *clksrc = NULL; struct clk *clk = NULL; unsigned long flags; unsigned int baud, quot; unsigned int ulcon; unsigned int umcon; unsigned int udivslot = 0; /* * 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, 115200*8); if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud); /* check to see if we need to change clock source */ if (ourport->clksrc != clksrc || ourport->baudclk != clk) { dbg("selecting clock %p\n", clk); s3c24xx_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; } if (ourport->info->has_divslot) { unsigned int div = ourport->baudclk_rate / baud; udivslot = udivslot_table[div & 15]; dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); } switch (termios->c_cflag & CSIZE) { case CS5: dbg("config: 5bits/char\n"); ulcon = S3C2410_LCON_CS5; break; case CS6: dbg("config: 6bits/char\n"); ulcon = S3C2410_LCON_CS6; break; case CS7: dbg("config: 7bits/char\n"); ulcon = S3C2410_LCON_CS7; break; case CS8: default: dbg("config: 8bits/char\n"); ulcon = S3C2410_LCON_CS8; break; } /* preserve original lcon IR settings */ ulcon |= (cfg->ulcon & S3C2410_LCON_IRM); if (termios->c_cflag & CSTOPB) ulcon |= S3C2410_LCON_STOPB; umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) ulcon |= S3C2410_LCON_PODD; else ulcon |= S3C2410_LCON_PEVEN; } else { ulcon |= S3C2410_LCON_PNONE; } spin_lock_irqsave(&port->lock, flags); dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n", ulcon, quot, udivslot); wr_regl(port, S3C2410_ULCON, ulcon); wr_regl(port, S3C2410_UBRDIV, quot); wr_regl(port, S3C2410_UMCON, umcon); if (ourport->info->has_divslot) wr_regl(port, S3C2443_DIVSLOT, udivslot); dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", rd_regl(port, S3C2410_ULCON), rd_regl(port, S3C2410_UCON), rd_regl(port, S3C2410_UFCON)); /* * 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 = S3C2410_UERSTAT_OVERRUN; if (termios->c_iflag & INPCK) port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY; /* * Which character status flags should we ignore? */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN; if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C2410_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 s3c24xx_serial_getclk(struct uart_port *port, struct s3c24xx_uart_clksrc **clksrc, struct clk **clk, unsigned int baud) { struct s3c2410_uartcfg *cfg = s3c24xx_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; s3c24xx_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) { s3c24xx_serial_setsource(port, clkp); s3c24xx_serial_getsource(port, &src); } clkp->divisor = src.divisor; } s3c24xx_serial_calcbaud(res, port, clkp, baud); best = res; resptr = best + 1; } else { resptr = res; for (i = 0; i < cfg->clocks_size; i++, clkp++) { if (s3c24xx_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; return best->quot; }
static unsigned int s3c24xx_serial_getclk(struct uart_port *port, struct s3c24xx_uart_clksrc **clksrc, struct clk **clk, unsigned int baud) { struct s3c2410_uartcfg *cfg = s3c24xx_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; s3c24xx_serial_calcbaud(res, port, clkp, baud); best = res; resptr = best + 1; } else { resptr = res; for (i = 0; i < cfg->clocks_size; i++, clkp++) { if (s3c24xx_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++) { 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 "best %p (deviation %d)\n", best, deviation); } printk(KERN_DEBUG "selected clock %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; return best->quot; }
static unsigned int s3c24xx_serial_getclk(struct uart_port *port, struct s3c24xx_uart_clksrc **clksrc, struct clk **clk, unsigned int baud) { struct s3c2410_uartcfg *cfg = s3c24xx_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; if (strcmp(clkp->name, "fclk") == 0) { struct s3c24xx_uart_clksrc src; s3c24xx_serial_getsource(port, &src); if (strcmp(src.name, clkp->name) == 0) { s3c24xx_serial_setsource(port, clkp); s3c24xx_serial_getsource(port, &src); } clkp->divisor = src.divisor; } s3c24xx_serial_calcbaud(res, port, clkp, baud); best = res; resptr = best + 1; } else { resptr = res; for (i = 0; i < cfg->clocks_size; i++, clkp++) { if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud)) resptr++; } } 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; } } } *clksrc = best->clksrc; *clk = best->src; return best->quot; }